Javascript 在这段代码中,为什么foo和this.foo引用不同的东西?

Javascript 在这段代码中,为什么foo和this.foo引用不同的东西?,javascript,closures,Javascript,Closures,代码如下: 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); } 这里的范围是全局的,上下文也是全局的。变量声明在全局上下文中设置同名属性。另一方面,在函数范围内,这不会发生

代码如下:

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);
}
这里的范围是全局的,上下文也是全局的。变量声明在全局上下文中设置同名属性。另一方面,在函数范围内,这不会发生

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();
即使我们将全局上下文传递到局部范围,在函数中声明变量也不会将其设置为全局上下文的属性

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

我想说的是:在全局范围中,变量声明修改全局上下文。但是在函数范围中变量声明不会修改函数的上下文,无论上下文是什么。为什么?

当您想到窗口上的全局范围时,它会有很大帮助。所以你可以说全局运行在窗口的上下文中。所以真的:

var x = 5;
console.log(x);
console.log(this.x);//both will print 5
在最后一行中,
这个
窗口
,因此您正在运行
console.log(window.x)

使用
bind
时,可以在“绑定”函数内更改
的引用。例如:

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

log(); // logs 10

log.bind({x: 20})()  // logs 20
bind
调用已使
日志中的
成为我们使用
{x:20}
创建的匿名对象的引用。您也可以这样做:

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

再仔细想想,这种行为是有道理的。感谢所有评论和回答的人。它帮助我更仔细地思考了这件事

  • 从基础开始,在JavaScript中,变量的作用域仅限于在其中定义的函数
  • 在全局范围中,var声明将var设置为全局上下文的属性(精细)
  • 如果我们希望在函数作用域中有相同的行为,那么var声明将修改函数的上下文对象。但这存在以下问题:

    a。如果函数的上下文是某个对象,则函数中的每个var声明都将被设置为该对象的属性。所以这会发生:

  • 函数具有对象上下文:

    //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。如果未设置函数的上下文,则其上下文为全局对象。我们已经知道这一点。但是,如果允许函数中的var声明以全局范围中的var声明相同的方式修改上下文,那么函数范围将变得毫无意义

    函数具有全局上下文:

    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
    

    这就是为什么
    var
    在函数内部和外部的工作方式不同。

    请参见下面的答案,以了解
    这个
    在js中的工作方式:谢谢,但不完全是我想要的。更新了我的问题,让它更清楚。这正是你想要的。参见该链接的规则3。未说明的假设是,我假设你知道全局变量和局部变量之间的区别。还有一个事实,在js中,全局变量被实现为全局对象的属性,“在js中,全局变量被实现为全局对象的属性”。这我知道。我想我总是隐式地假设局部变量是作为局部上下文对象的属性实现的,当事实证明并非如此时,我感到惊讶。谢谢,这里没有本地对象。这里有一个
    arguments
    对象,这个对象的想法大致相同,但工作方式不同。对不起,与另一个对象的注释相同(现在已删除答案)。我理解bind如何改变上下文。我不明白的是,为什么变量声明会更改全局范围内的上下文对象(通过将声明的变量添加为window的属性),而不是函数范围内的上下文对象(函数的this对象不会获得新属性)。另一位回答者的评论说“这就是JS的设计”。如果这真的是答案,好吧,但如果有比这更深刻的答案,我想know@Jayraj默认的全局上下文是什么<代码>窗口
    。因此,
    这个
    总是有一个值——如果没有固有的值,它将是全局的,它将是
    窗口
    。如果您在声明变量时没有放入
    var
    ,则它是全局变量,并在
    window
    上运行。如果您在变量上放置了
    var
    ,并且您处于全局范围内,那么它也将进入
    窗口
    。那部分有意义吗?是的。这一切都有道理。但是,如果在变量上放置
    var
    ,并且您在函数范围内,则var不会出现在函数的上下文中(上下文实际上是什么并不重要;可能是
    window
    也可能是另一个对象)。仅仅在函数范围内就会改变var语句的行为;它不会像在全局范围中那样修改
    (同样,即使函数的上下文是
    窗口
    )。你可能认为我在这里很迟钝,但这对我来说似乎是不可思议的微妙行为。@Jayraj我同意var在全局范围内的说法,这是一种非常微妙和奇怪的行为。我认为值得记住的是,JavaScript是在大约7天的时间内创建的,当时人们正疯狂地想要发布一些东西。但即便如此,也有一些非常有趣的微妙行为。实际上,这些通常不会出现问题——事实上,在我的经验中,globals是一个非常糟糕的做法,在使用CommonJS时,我很少需要考虑
    窗口
    和全局范围。
    
    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