isaac9A
isaac9A

Reputation: 903

Javascript Callback Scoping Issue

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

Answers (2)

dimitar veselinov
dimitar veselinov

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

T.J. Crowder
T.J. Crowder

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

Related Questions