var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
我知道let
定义的变量具有块级作用域,但还是不明白为什么输出的是6,求解释原理。
另外这里也有闭包形成吧?
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
我知道let
定义的变量具有块级作用域,但还是不明白为什么输出的是6,求解释原理。
另外这里也有闭包形成吧?
i是for循环这个作用域的局部变量,每次进入for循环都会重新创建,所以i对应的值为1、2...6。我理解,这里应该是有形成闭包的,闭包其实就是函数持有其外层作用域的引用,能够访问外层作用域的变量。如果for循环里面没有那个打印函数,for语句执行完之后,这个块级作用域应该会销毁掉。由于循环中的函数,for执行完之后i并没有回收,这和通常的函数级作用域嵌套道理貌似是一样的。
块级作用域:{{let a="block scope"} {...a is undefined,you can redefine,but the first a can not be changed}}
代码,改let为var:
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
console.log(i) =>10////i为全局变量,循环结束后值为10
console.log(a6 //=>10
console.log(a[6].toString())=> function () {console.log(i);}
a=>[function () {console.log(i);},function () {console.log(i);},...]//i为10
换成let,记住块级作用域的特性;
a同样为[function () {console.log(i);},function () {console.log(i);},...]//i递增,互相不影响(块级作用域,或者你可以理解为所谓的十个平行作用域)。
。。。。。。。。。。。。。。。。。。。。。。。。。。分割线
但是 以为这样这样理解就正确了吗?naive
用var a同样为[function () {console.log(i);},function () {console.log(i);},...]//我没有块级作用域,但是我有函数作用域分割啊,我同样的相互不影响。所以还原问题的本质:
看代码:var
执行结果(后面截不到)
每一次循环,i都会++,a中各元素的i都会被重新覆盖。
let
执行结果
每一次循环i都会++,但是a中各元素的i都没有被重新覆盖。而函数在声明时作用域链就已经确定,为什么不能被覆盖呢。要知道在某些方面块级作用域的表现和函数作用域的表现类似:
执行结果
在函数内声明的变量在函数体及其嵌套的函数中都是defined,但是其好像又破坏了(函数在声明时作用域链就已经确定)这个规则:for循环体中的i不能覆盖a中元素(函数)的i!ok按目前的理论:let的表现就是这样。。。
蹩脚(函数在声明时作用域链就已经确定)的解释就是:i为for循环体中的变量,只在循环体中有定义,而a为全局变量,i的手没那么长。
没看出什么闭包,也没觉得跟 let 有啥关系。就普通的一个循环,把表达式储存在数组中:
[function () {console.log(0)}, function () {console.log(1)}, function () {console.log(2)} ...]
所以 a[6]
应该是表达式 function () {console.log(6)}
本身。所以结果是:
(function () {console.log(6)})()
,那自然就是 6 咯。
27 回答13.8k 阅读
8 回答3.5k 阅读✓ 已解决
6 回答1.3k 阅读✓ 已解决
5 回答5.3k 阅读✓ 已解决
4 回答1.6k 阅读✓ 已解决
3 回答1.7k 阅读
4 回答2.3k 阅读✓ 已解决
let定义的变量i具有块级作用域,作用域是for循环所包含的语句块。
这个for循环最终执行了10次,实际上会产生10个互相平行的块级作用域。在每个作用域里面,i的值分别是0,1,2,..,8,9。
当调用a[6]时,执行到console.log(i)这行语句时,解释器会沿着作用域链寻找i的值,结果向上一层就是这10个平行作用域中的第7个,其中i的值为6,于是就打印出了6。
这段代码如果被翻译成ES5代码,应该如下:
实际上,使用babel 6.6.5 babel-preset-es2015 6.6.0 的转换结果如下: