请解释两个代码之间的区别。为什么两者的输出都不同。
'use strict';
let printNumTwo;
for (let i = 0; i < 3; i++) {
if (i === 2) {
printNumTwo = function() {
return i;
};
}
}
console.log(printNumTwo());
'use strict';
let printNumTwo;
let i;
for (i = 0; i < 3; i++) {
if (i === 2) {
printNumTwo = function() {
return i;
};
}
}
console.log(printNumTwo());
答案 0 :(得分:3)
区别在于声明i
的范围。
在循环块范围内声明i
'use strict';
let printNumTwo;
for (let i = 0; i < 3; i++) { // block scope
// each time we have new variable i
if (i === 2) { // block scope
printNumTwo = function() {
return i; // captures the one that was equal 2
};
}
}
// console.log(i) // throws ReferenceError
console.log(printNumTwo());
在全局范围内声明i
'use strict';
let printNumTwo;
let i; // globally scoped
for (i = 0; i < 3; i++) {
if (i === 2) {
printNumTwo = function() {
return i; // captures globally scoped i which will be mutated i++
};
}
}
console.log(i) // prints 3
console.log(printNumTwo());
UPD一些文档 Spec
13.7.4.8运行时语义:
ForBodyEvaluation ( test, increment, stmt, perIterationBindings, labelSet )
抽象操作 ForBodyEvaluation with arguments test,increment,stmt, perIterationBindings和labelSet按如下方式执行:
- 让
V
成为undefined
。- 表演?
CreatePerIterationEnvironment(perIterationBindings)
。- 重复,
醇>...
即表演?
CreatePerIterationEnvironment(perIterationBindings)
。F。如果
increment
不是[空],那么......
基本上在PerIterationEnvironment
部分之前创建了新的increment
。因此函数将捕获i === 2
。
答案 1 :(得分:1)
我只会解释第一个例子,因为第二个例子很明显
'use strict';
let printNumTwo;
for (let i = 0; i < 3; i++) {
if (i === 2) { // block scope
printNumTwo = function() {
return i;
};
}
}
console.log(i)
console.log(printNumTwo());
当你使用let inside for循环时,这意味着变量i仅在for scope中定义,所以在i等于2的范围内我们设置变量printNumTwo,当我们再次执行i ++时,我改变了它值为3,但不会更改其在for范围内的值,它仍然等于2 ,这意味着如果您想以某种方式访问i值,它总是等于2
for (let i = 0; i < 3; i++) {
console.log(i) // prints 0,1,2
}
console.log(i) // undefined
要记住的是,即使我等于2并且我们做了++,它也不会在for scope中改变它的值,因为我是用let定义的