Reputation: 903
I am reading Douglas Crockford's book on Javascript and having some issues with the function scoping section. I was under the impression that a callback function's this value is bound to the this value of the function calling the callback (in this case doSomethingAsync). However, when I run this code, foo is printed, but as far as doSomethingAsync is concerned, foo is undefined. Shouldn't this mean that the callback doesn't have access to this var as well?
function doSomething() {
var foo = "foo";
doSomethingAsync(function callback() {
console.log(foo); //prints foo
});
}
Upvotes: 0
Views: 58
Reputation: 138
First the callback function checks to see if it has any "foo" var in its own scope. When it finds that there isnt any, it checks its "parent" scope for a "foo" var. It finds it there and uses it.
If you define a new var foo inside the callback, that one would be used instead.
Upvotes: 1
Reputation: 1074295
this
and variables are very different from one another.
this
is primarily set by how a function is called, not where it's defined, although bound functions and ES6's arrow functions change that (more below). Your callback isn't bound and isn't an arrow function, so the value of this
within the callback you're giving doSomethingAsync
will be determined by how doSomethingAsync
calls that function. If it calls it just as a standalone function:
callback();
...then this
will be undefined
(in strict mode) or a reference to the global object (in loose mode).
But if it calls it specifying a this
value:
// By making it an object property and using that to call it:
var obj = {callback: callback};
obj.callback(); // `this` will be `obj`
// By using Function#call or Function#apply
callback.call(foo); // `this` will be `foo`
...then this
will be something different.
More (on my blog):
The variables in scope for a function, though, are determined by where that function is defined. Your callback is called a closure, which means it has an enduring reference to the context in which it was created (and the context around that, and so on up to and including the global context), including the variables and some other things in that context. So when your callback references foo
, the JavaScript engine first looks within the callback and, not finding anything there called foo
, looks at the containing context. Finding a foo
there, it uses it.
That context reference the closure has does not include this
, however (except for arrow functions), because this
is more like a function argument than a variable (except for arrow functions).
More (on my blog):
"Bound" functions are functions that you get from Function#bind
. One of the features of them is that their this
value is set by the argument you give Function#bind
, ignoring the one supplied when they're called (if any).
ES6 "arrow" functions do inherit their this
from the context where they were created, making them very different from other kinds of functions.
Upvotes: 3