Javascript 为什么结果不同(使用var和let)?
这将使用Javascript 为什么结果不同(使用var和let)?,javascript,arrays,ecmascript-6,closures,Javascript,Arrays,Ecmascript 6,Closures,这将使用var var a = []; for (var i = 0; i < 10; i++) { a[i] = function() { console.log(i); }; } a[6](); // 10 我不明白为什么结果不同。有人可以指导我吗?我认为最好不要在循环中定义函数,只需一个函数定义,返回一个: ECMA6: for (let i = 0; i < 10; i++) { } console.log(i); // i is not d
var
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function() {
console.log(i);
};
}
a[6](); // 10
我不明白为什么结果不同。有人可以指导我吗?我认为最好不要在循环中定义函数,只需一个函数定义,返回一个: ECMA6:
for (let i = 0; i < 10; i++) { }
console.log(i); // i is not defined
for(设i=0;i<10;i++){
console.log(i);//我没有定义
编辑:正如我在对您的问题的评论中所述,这很可能是您使用的transpiler的副作用。Firefox支持块作用域,两个版本的循环都将
10
作为输出(它们应该这样做)。根据规范,这是正确的行为。var
和let
的行为定义为不同的
请参见第页的规范。根据这一点,使循环内声明的函数在块作用域循环索引的当前值上闭合的相关概念称为“每次迭代绑定”和“每次迭代环境”
Babel正确地处理它,生成以下代码:
var a = [];
var _loop = function (i) {
a[i] = function () {
console.log(i);
};
};
for (var i = 0; i < 10; i++) {
_loop(i);
}
var a=[];
var_loop=函数(i){
a[i]=函数(){
控制台日志(i);
};
};
对于(变量i=0;i<10;i++){
_回路(i);
}
通过将for
循环的内容隔离到由索引参数化的单独函数中,实现了for(let
)的语义。通过这样做,函数不再关闭for循环索引,并且i
在创建的每个函数中分别处理。因此答案是6
Traceur没有生成正确的结果。它生成10
因此,已经被问了100次的著名问题,关于为什么我的函数在循环中声明并在索引上结束时使用了循环索引的“错误”值,应该不再问了
这个问题有点微妙,仅仅宣布“当然,let
是块范围的”。我们知道这一点。例如,我们知道它在if
块中是如何工作的。但是,在for
的上下文中,这里发生的是对块范围的一点扭曲,包括我在内的许多人至今都不知道。它实际上是在块之外声明的一个变量(如果您认为块是for
语句的主体),但在循环的每个迭代中都有一个独立存在
有关更多信息,请参阅
为什么ES6和ES5的结果不同
因为let
和var
是不同的。let
是块作用域,而var
是函数作用域
在第一个示例中,只有一个变量i
。您创建的每个函数都引用同一个变量i
。在调用a[6]()
时,i
的值为10
,因为这是循环的终止条件
在第二个示例中,循环的每个迭代都有自己的变量i
。它的工作原理与其他具有块范围的语言完全相同。生成的数组由函数组成,每个函数体如下所示:
console.log(i);
i
的值取决于我们是使用var
还是let
来声明变量
var
(ECMAScript 5和6)
这里的i
是一个全局变量,退出循环后其值为10
。这是记录的值
let
(ECMAScript 6)
这里的i
是一个局部变量,其作用域仅限于for
语句。此外,此变量在每次迭代时都会得到一个新的绑定。这可以通过您的代码得到最好的解释:
“严格使用”;
var a=[];
var_loop=函数(i){
a[i]=函数(){
控制台日志(i);
};
};
对于(变量i=0;i<10;i++){
_回路(i);
}
a[6]();/6
例如,在第七次迭代中,i
的值将是6
(从零开始计数)。在迭代中创建的函数将引用此值。请参见此处两个示例生成10 for Me您可以通过ecma6构建for ecma6您应该这样写:@dukegod我不完全理解您的意思,但这并不能回答为什么OP会看到两个不同的结果的问题。@torazaburo如果您跳过眉毛的话er支持let
(比如Firefox)而不是使用transpiler,这两个版本都生成10。我相信OP结果的奇怪之处更多地与transpiling有关,而不是ECMA6规范中let
的行为。是的,我理解它应该如何工作。但OP的问题不是“为什么是10”,这是一个完全合理但独立的问题,但更确切地说,是“为什么行为不同”。我认为对上述问题的正确答案是“行为不同,因为您使用的是一个有小车的transpiler”…不确定你是如何得到10的?@FelixKling抱歉,脑动脉瘤,Babel和Traceur的交换输出。修复了。啊。如果Traceur真的为第二个示例生成了10,那么它是不正确的。let
是块范围的。你对术语“局部变量”的使用是非标准的。
for (let i = 0; i < 10; i++) { }
console.log(i); // i is not defined
var a = [];
var _loop = function (i) {
a[i] = function () {
console.log(i);
};
};
for (var i = 0; i < 10; i++) {
_loop(i);
}
console.log(i);
"use strict";
var a = [];
var _loop = function(i) {
a[i] = function() {
console.log(i);
};
};
for (var i = 0; i < 10; i++) {
_loop(i);
}
a[6](); // 6