Javascript 当分配给新变量时,循环内的计数器值会发生变化

Javascript 当分配给新变量时,循环内的计数器值会发生变化,javascript,scope,Javascript,Scope,我在学JS。为什么日志funcs2[1]()日志4和funcs[1]()日志5 请注意,这不是的副本。我知道funcs[1]()记录5(而不是1),因为调用的函数绑定到i的当前值,循环终止时该值为5 但这不是我的问题。我想知道为什么funcs2[1]()日志4,而不是日志5 var funcs = []; for (var i = 0; i < 5; i++) { funcs.push(function () { return i; }); } conso

我在学JS。为什么日志
funcs2[1]()日志4和
funcs[1]()日志5

请注意,这不是的副本。我知道
funcs[1]()
记录
5
(而不是1),因为调用的函数绑定到
i
的当前值,循环终止时该值为5

但这不是我的问题。我想知道为什么
funcs2[1]()日志4,而不是日志5

var funcs = [];
for (var i = 0; i < 5; i++) {
    funcs.push(function () {
        return i;
    });
}

console.log(funcs[1]());
5

var funcs2 = [];
for (var i = 0; i < 5; i++) {
    var x = i;
    funcs2.push(function () {
        return x;
    });
}

console.log(funcs2[1]());
4
var funcs=[];
对于(变量i=0;i<5;i++){
函数推送(函数(){
返回i;
});
}
console.log(funcs[1]());
5.
var funcs2=[];
对于(变量i=0;i<5;i++){
var x=i;
funcs2.push(函数(){
返回x;
});
}
console.log(funcs2[1]());
4.

因为当i增加到5时,它不会进入循环,所以最后x是4


这是一个著名的JS闭包问题,内部函数只将父上下文的变量对象保留在其内部
[[scope]]
属性中,而不保留变量。因此,当循环完成时,父对象的VARABLE对象中的
i
等于5,而x等于4。

因为当i增加到5时,它不会进入循环,因此最终x等于4


这是一个著名的JS闭包问题,内部函数只将父上下文的变量对象保留在其内部
[[scope]]
属性中,而不保留变量。因此,当循环完成时,父对象的VARABLE对象中的
i
等于5,而x等于4。

由于javascript中没有块作用域,在两个循环完成后,变量
i
的值在这两种情况下都是
5


然而,在第二种情况下,
x
的值是
4
,因为这是最后一个迭代索引,
i++
发生在
x=i
赋值之后。

由于javascript中没有块范围,在两个循环完成执行后,变量
i
的值在这两种情况下都是
5


然而,在第二种情况下,
x
的值是
4
,因为这是最后一次迭代索引,
i++
发生在
x=i
赋值之后。

对不起,我对原始帖子的编辑被拒绝。为了进一步讨论这一点,我用另一个案例作了另一个回答:

var funcs3 = [];
function foo() {
    for (var k = 0; k < 5; k++) { // k is in foo's scope
        funcs3.push(function () {
            return k;
        });
    }
}

foo(); // k can't be accessed after from here
console.log(funcs3[1]()); // 5, k is still in closure 
var funcs3=[];
函数foo(){
对于(var k=0;k<5;k++){//k在foo的范围内
funcs3.push(函数(){
返回k;
});
}
}
foo();//从这里以后无法访问k
console.log(funcs3[1]());//5,k仍处于关闭状态

对不起,我对原始帖子的编辑被拒绝。为了进一步讨论这一点,我用另一个案例作了另一个回答:

var funcs3 = [];
function foo() {
    for (var k = 0; k < 5; k++) { // k is in foo's scope
        funcs3.push(function () {
            return k;
        });
    }
}

foo(); // k can't be accessed after from here
console.log(funcs3[1]()); // 5, k is still in closure 
var funcs3=[];
函数foo(){
对于(var k=0;k<5;k++){//k在foo的范围内
funcs3.push(函数(){
返回k;
});
}
}
foo();//从这里以后无法访问k
console.log(funcs3[1]());//5,k仍处于关闭状态

所以最后一次计算
i++
(i递增到5),循环体不执行,在funcs2中,由于我返回x,它会被固定在4?是的,
i
总是最后一次递增,然后再次比较
i<5
,但是当
i
==
5
时,您永远不会进入循环。放置
console.log(x,i)
var x=i
之后,您将看到。是的,我刚刚将i记录在
funcs
的循环中,并发现它从未达到5。函数范围不是OP问题的根本原因,关闭机制是。因此上次对
i++
进行了评估(i增加到5),循环体没有执行,在funcs2中,由于我返回x,它将被固定在4?是的,
I
总是最后一次递增,然后再次比较
I<5
,但是当
I
==
5
时,您永远不会进入循环。放置
console.log(x,i)
var x=i
之后,您将看到。是的,我刚刚将i记录在
funcs
的循环中,发现它从未达到5。函数范围不是OP问题的根本原因,关闭机制是。谢谢。你的答案也是正确的,但是我选择了@ dfsq,因为它更好。不必介意,但我会考虑这是一个关闭问题,而不是函数/块范围问题。理解闭包是JS学习中的一条关键路径,我们正在谈论同样的事情。问题是因为没有块级别的作用域。因此,闭包的问题就出现了。如果
迭代的每个
内部都有单独的作用域,则闭包中的值是正确的。@dfsq-实际上它们并不完全相同。看看我更新的funcs3案例,
k
foo
的范围内,似乎
k
应该在
foo
结束执行时被销毁,
funcs3[1]
永远不能引用
k
,但实际上
funcs3[1]
通过闭包保留另一个对
k
的引用,这样
k
就不会被GCed。谢谢。你的答案也是正确的,但是我选择了@ dfsq,因为它更好。不必介意,但我会考虑这是一个关闭问题,而不是函数/块范围问题。理解闭包是JS学习中的一条关键路径,我们正在谈论同样的事情。问题是因为没有块级别的作用域。因此,闭包的问题就出现了。如果
迭代的每个
内部都有单独的作用域,则闭包中的值是正确的。@dfsq-实际上它们并不完全相同。看看我更新的funcs3案例,
k
foo
的范围内,似乎
k
应该在
foo
结束执行时被销毁,
funcs3[1]
永远不能引用
k
,但实际上
funcs3[1]
通过闭包保留对
k
的另一个引用,以便
k
不进行GCed。