Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 为什么结果不同(使用var和let)?_Javascript_Arrays_Ecmascript 6_Closures - Fatal编程技术网

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