Jay
Jay

Reputation: 3531

In this code, why do foo and this.foo refer to different things?

Here's the code:

for (var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i); //prints 9 10 times
        console.log(this.i); //prints 0, 1, 2...9
    }.bind({i:i}), i * 1000);
}

Why do i and this.i refer to different things?

Contrast this to a bit of code executed on the global scope:

var x = 5;
console.log(x);
console.log(this.x);//both will print 5

Here the scope was global, and so was the context. A variable declaration set a property of the same name on the global context. On the other hand, within a function scope, this doesn't happen.

var a = function() {
    var x = 5;
    console.log(x); //5
    console.log(this.x); //undefined
    console.log(i);  //undefined
    console.log(this.i);  //10

}.bind({i: 10});
a();

Even if we pass the global context into the local scope, declaring a variable within the function doesn't set it as a property of the global context.

var a = function() {
    var x = 5;
    console.log(x); //5
    console.log(this.x); //undefined
}.bind(window);
a();
console.log(x); //undefined
console.log(this.x); //undefined

What I'm trying to say is this: in the global scope, a variable declaration modifies the global context. But in a function scope, a variable declaration doesn't modify the function's context, no matter what the context is. Why?

Upvotes: 6

Views: 836

Answers (2)

Jay
Jay

Reputation: 3531

Thinking about this a bit more, this behavior makes sense. Thanks to everyone who commented and answered. It helped me think through this thing a bit more.

  1. Starting from basics, in JavaScript, the scope of a variable is limited to the function that it is defined in.
  2. In global scope, a var declaration will set the var as a property of the global context (fine)
  3. If we wanted the same behavior in function scope, the var declaration would modify the function's context object. But this has the following problems:

    a. If the context of a function is some object, every var declaration within the function would get set as a property on the object. So this would happen:

Function has object context:

//if var declarations inside functions modified context
//this doesn't happen in reality
var ctx = {b: 5};
var a = function() {
    var c = 7;
    this.b = 10;
}.bind(ctx);
a();
console.log(ctx.b); //10, as expected
console.log(ctx.c); //7, wtf? I never set this

b. If the context of the function isn't set, its context is the global object. We already know this. But if var declarations within functions were allowed to modify context in the same way that var declarations in global scope do, then functional scope would become meaningless

Function has global context:

function a() {
    var b = 5;
    this.c = 10; //this refers to window. it is this function's context
}
a();
console.log(b); //outputs 5 if function vars could modify context, which means functional scope is dead
console.log(c); //outputs 10, as expected

That's why var works differently in a function and outside of it.

Upvotes: 0

Cymen
Cymen

Reputation: 14419

It helps a lot when you think of global scope being on window. So you can say global runs in the context of window. So really:

var x = 5;
console.log(x);
console.log(this.x);//both will print 5

In the last line, this is window so you are running console.log(window.x).

When you use bind, you change the reference of this inside of the "bound" function. For example:

var x = 10;
function log() {
  console.log(this.x);
}

log(); // logs 10

log.bind({x: 20})()  // logs 20

The bind call has made this within log be a reference to the anonymous object we created with {x: 20}. You could also do this:

var myObject = {x: 50};
log.bind(myObject)(); // logs 50

Upvotes: 2

Related Questions