I am really confused about the value of this in callbacks, well I know that the value of this is always taken from where it was called, but here in the below code, i can't figure out what's happening.
userSchema.pre("save", function(next) {
let user = this;
bcrypt.hash(user.password, 10, function(err, hash) {
if (err) {
next(err)
} else {
user.password = hash;
next();
}
})
});
I was watching a tutorial of node js with mongoose, so the instructor said:
In the context of this callback function, the word this refers to the object, which is
let userSchema = new mongoose.Schema({
password: {
type: String,
required: true
}
});
shouldn't the user = this here refer to Node Global Object instead of that object?
so I'm really confused how this happens, for Example, if I try to mimic this code behaviour in simple JavaScript.
function UserSchema() {
this.pre = function(cb) {
return cb();
}
}
function Bycrypt() {
this.hash = function(cb) {
return cb();
}
}
userSchema.pre(function() {
var user = this;
bycrypt.hash(function() {
console.log(user)
})
});
this will log user as the Window Object because the callback function was called in the context of Window.
well, I know that it's a weird question to ask.
this in JavaScript functions refers to execution context and in a case of normal (not ES6-specific "arrow" function) normally equals to context, function was called in. However "this" can be changed by e.g. using bind, call or apply methods of the Function object to pass different value for this.
You can read, for example, this article on MDN for details.
This is not a weird question at all, the this keyword is often a source of confusion because of its implicit nature :-) Anyway, I have no idea about how the pre function is implemented, but we can easily imagine something like that :
schema = {
whoami: "a schema"
};
schema.pre = function (cb) {
return cb.call(this);
}
schema.pre(function () {
console.log(this.whoami);
});
The call function is a JavaScript builtin that allows to change the default subject (window) of a function. Browsing the source code I have found something that seems to be the pre function (not 100% sure) : https://github.com/Automattic/mongoose/blob/master/lib/schema.js#L1138. As you can see they use the apply builtin which has the same effect as call. Let's see how they differ :
function f(a, b) {
console.log("I am", this.whoami);
console.log("Arguments :", "[" + a + ", " + b + "]");
}
f.call({ whoami: "A" }, "b", "c");
f.apply({ whoami: "X" }, ["y", "z"]);
I believe that this can be a good starting point to investigate. I let you dive into the source code to find the nature of this.s.hooks and this.queue(...) :-)
this binds to the call site of a function. It can also be bind to where you specify it to bind to using function methods like call, apply, and bind.
function foo () {
var a = 5;
console.log(this.a);
}
var a = 2;
foo(); // 2
With ES6 arrow function, this is bound to the lexical scope.
Related
I'm trying to understand exactly how this Once function by David Walsh works:
`
function once(fn, context) {
var result;
return function() {
if(fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
};
}
// Usage
var canOnlyFireOnce = once(function() {
console.log('Fired!');
});
canOnlyFireOnce(); // "Fired!"
canOnlyFireOnce(); // nada
`
I understand it takes a function as a argument, and returns a function that calls the passed function only once.
But I'm trying to understand what each part is doing. Can anyone help explain? especially this part:
result = fn.apply(context || this, arguments);
Why the OR sign? what is "this" and how is it getting the arguments from fn? What purpose does 'context' serve?
I wrote a similar once() function for school that returns the result of the passed function, and stores the result to return it again if the function attempts to get called again. It took a lot of trial and error, and I'm just trying to get a firm grasp on all the component parts of how this works.
`
function add(x, y) {
return x + y;
}
function once(fn) {
let timesRan = 0;
let result;
function doOnce() {
if (timesRan === 0) {
timesRan = 1;
result = fn.apply(this, arguments); //I don't understand how this gets the arguments from AddOnce
console.log(`did it once: ${result}`)
return result;
} else {
return result;
}
}
return doOnce;
}
var addOnce = once(add);
console.log(addOnce(1, 2)); // test first call, expected value: 3
console.log(addOnce(2, 5)); // test second call, expected value: 3
console.log(addOnce(8, 22)); // test third call, expected value: 3
`
The concept behind this in JavaScript is confusing, because when I write a function such as:
function getPersonName() {
return this.name
}
I expect that this be defined as a some object with a name attribute. Depending on the scope, I may have this be defined and no problems! But in order for a function such as the above to properly reference this, we need to tell it what it should reference when we use that keyword.
For example, it allows us to do the following:
var canOnlyFireOnce = once(function() {
console.log(this.name)
}, {name: "John"});
canOnlyFireOnce() // prints John
canOnlyFireOnce() // nada
It may be helpful to understand the bind function's use cases in JavaScript to understand why having this (no pun intended) is useful.
The meaning of the this context in function.apply is already explained in rb612's answer.
For the question about arguments, you need to know that
the arguments object is a local variable available within all non-arrow functions. You can refer to a function's arguments inside that function by using its arguments object.
I am studying JavaScript syntax. I occasionally see a pattern that confuses me: an equals sign on the right hand side of the arrow. For example, something like this:
.then(data => myVariable = data)
I don't know what is going on in that syntax. It looks like it is taking the value of data and assigning it to the variable named myVariable. Can somebody explain this?
You're right. It's an arrow function (without an accompanying block) that "returns" an assignment expression - in effect doing an assignment of data's value to myVariable and returning the right hand side, though that might not be utilized in this case.
In a more simplified case:
let foo = 3;
function foobar(callback) {
const result = callback(5); //call callback with 5 as argument
console.log(result); //5
}
foobar(five => foo = five); //assigns 5 to foo
console.log(foo); //5
This is generally not the most readable option and your question proves this. I would recommend adding a block like so (if you don't intend on actually returning the right hand side value):
myPromise.then(data => {
myVariable = data;
});
In which case there is no implicit return of the assignment expression's right hand side and makes the intent clearer. Also, assignments such as what you're doing right with what I assume to an asynchronous promise are not encouraged.
Maybe look into async/await or other new ES features to deal with asynchronous code other than using variable assignments which may run into some problems if not used correctly.
This is called fat arrow function in ES 6 . It is used for many purposes like
1.Arguments
If we want to pass and argument to a function.
Old Syntax :
let sum = function(x,y){
return x+y;
}
New Syntax with fat arrow
let sum = (x,y) => x+y;
//ES5
var setNameIdsEs5 = function setNameIds(id, name) {
return {
id: id,
name: name
};
};
// ES6
var setNameIdsEs6 = (id, name) => ({ id: id, name: name });
console.log(setNameIdsEs6 (4, "Kyle")); // Object {id: 4, name: "Kyle"}
Note : Return statement is not required in fat arrow of it is only one line .
2. Anonymous Function.
// ES5
API.prototype.get = function(resource) {
var self = this;
return new Promise(function(resolve, reject) {
http.get(self.uri + resource, function(data) {
resolve(data);
});
});
};
Using an arrow function, the same result can be achieved more concisely and clearly:
// ES6
API.prototype.get = function(resource) {
return new Promise((resolve, reject) => {
http.get(this.uri + resource, function(data) {
resolve(data);
});
});
};
I've recently used a nice library for node.js called Kue.
I wanted to get some better understanding of what's going so I started reading the code...
I stumbled on to a piece of code and my mind went "WTF!!?!#$#!$"...
This is the code:
function get(obj) {
var pending = 0
, res = {}
, callback
, done;
return function _(arg){
switch (typeof arg) {
case 'function':
callback = arg;
break;
case 'string':
++pending;
obj[arg](function(err, val){
if (done) return;
if (err) return done = true, callback(err);
res[arg] = val;
--pending || callback(null, res);
});
break;
}
return _;
};
}
which being used like this:
exports.stats = function(req, res){
get(queue)
('inactiveCount')
('completeCount')
('activeCount')
('failedCount')
('delayedCount')
('workTime')
(function(err, obj){
if (err) return res.send({ error: err.message });
res.send(obj);
});
};
.
.
.
Are those functions on functions?!
How are they aware of each other?
What is that '_'(underscore) on the 7th row of the function?
Could someone please help me understad what's goin' on over there? :)
Functions can indeed return functions. Take this function, for example:
function func(text) {
alert(text);
return func;
}
Obviously the return value of any invocation of func will be, again, func, so you can use it like this:
func("hello")("world");
…and you'll get two alerts: first "hello", and then "world".
Next, there's something called a named function expression. You might have seen anonymous function expressions before:
doSomething(thing, function(err) {
// operation completed or something
});
That, of course, is great for simple things, but sometimes you want the function to have a name so it can refer to itself. As Kolink mentioned, if you just want to recurse, there's arguments.callee, which refers to the function currently executing, but there is another way: you can give the function a name visible only within the function while still having it be a function expression:
doSomething(thing, function myself(err) {
// ^^^^^^
// now I can refer to myself as myself!
});
An underscore is a valid identifier, so they're basically just combining these techniques in a way that may be difficult to understand.
I want to define a read-only object property that asynchronously fetches a value and then returns it using the new EcmaScript 5 getters.
However, the property always returns undefined even though magicValue in the example code below is definitively never undefined. Also, when I just return 'xxx'; the printed value is still undefined. It only works when I return outside the callback function.
It seems like return is being executed immediately regardless of whether the callback of myAsyncFunction is called.
I am not sure whether this a bug in in V8 or if I am abusing JavaScript's getters.
Can I get this to work? I thought, since I can use getters and setters now, I will use getters/setters to read and write properties and regular functions to do certain tasks.
var User = function (id) {
this.id = id;
};
Object.defineProperty(User.prototype, 'magic', {
get : function () {
myAsyncFunction(function (magicValue) {
return magicValue;
});
}
});
var u = new User(5);
console.log(u.magic);
Prints undefined.
Asynchronous operations, these days, are typically handled with Promises. When you invoke your getter, it returns a promise, which you can attach a callback with using the 'then()' method.
Object.defineProperty(User.prototype, "magic", {
get: function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(JSON.stringify({
magic: 'value'
}));
}, 1000);
});
}
});
Here is a working example:
https://jsfiddle.net/tw6gaudz/2/
Thanks #utkanos for your help.
JavaScript won't acynchronously return a getter function's value because getters are synchronous.
You could use a "setter":
var User = function (id) {
this.id = id;
};
Object.defineProperty(User.prototype, 'magic', {
set : function (value) {
setTimeout(value.bind(0, "hello"), 1000);
return true;
}
});
var a = new User(5);
a.magic = function(msg){
alert(msg);
};
I'm trying to go through the source code for the node chat demo seen here. In the server.js file and fu.js file there is a function referenced as callback() seen here:
function loadResponseData(callback) {
if (body && headers && !DEBUG) { //if they already have value
callback();
return;
}...
but as far as I can tell this function is never defined and I cannot find it as a module function of node.js, a function of jquery or a standard function for javascript.
I think I understand how callback functions work but I'm not familiar with this call and it is used frequently enough in this app that I would like a firm understanding of what it is and where it comes from.
So my question is three fold:
1) where is the function based: (javascirpt, jquery, node.js, particular to this app)
2) where can I find the source code for this function?
3) how is this function interacting with the functions it is called in?
It is the argument of the loadResponseData function. If you call loadResponseData like this:
loadResponseData(function () {
res.writeHead(200, headers);
res.end(req.method === "HEAD" ? "" : body);
});
then callback() in loadResponseData will execute
res.writeHead(200, headers);
res.end(req.method === "HEAD" ? "" : body);
EDIT to clarify the question in comments:
You could say it's a feature of JavaScript. The important thing here is that JavaScript is a functional language: it has functions as a data type in their own right. Thus, you can save them in variables (and indeed, that's all every function name in JS is - a variable with a function as its content), and pass them along in an argument list (as is demonstrated here). There is nothing magical about the name callback - it could have as well been fn or whoopsie7. To demonstrate:
var doubleAndOne = function(a) {
return a * 2 + 1;
}
function doItTwice(k, whoopsie7) {
whoopsie7(whoopsie7(k));
};
doItTwice(5, doubleAndOne); // result is 23
function(...) {...} is called an anonymous function: it is pure function value, taking some arguments and doing something with them, but it is not assigned to any name. To make a function with a name, you can assign this to a variable, or pass it as a parameter, just like you could with any other value. For example, there is very little difference between:
var five = function() { return 5; };
var doubleFuncValue = function(fn) { return fn() * 2; };
doubleFuncValue(five); // result 10
and
var five = 5;
var doubleNumValue = function(n) { return n * 2; };
doubleNumValue(five); // result 10