javascript - 学习ES6时let用于for循环时,函数里console的问题
PHP中文网
PHP中文网 2017-04-11 09:01:02
[JavaScript讨论组]
 var a = [];
    for (let i = 0; i < 10; i++) {
      a[i] = function () {
        console.log(i);
      };
    }
    a[6](); //6
    console.log(a[6]); //  function(){console.log(i)} 

既然循环结束后,数组a的每一项都是function(){console.log(i)},那么a[6]()输出是6是怎么实现的?难道let保存了10个状态?

之前搞错了,在外面不能输出i,以下是原来的问题

===============================

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); //6
console.log(a[6]); //  function(){console.log(i)}
console.log(i);  //10

a[6] = function(){console.log(i)}
而此时i=10,那么a[6]为啥不是10

PHP中文网
PHP中文网

认证高级PHP讲师

全部回复(6)
高洛峰
> console.log(i);  //10
ReferenceError: i is not defined

let是块作用域声明,出了for循环就失效了~


a[6](); //6
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}

在匿名函数作用域中log(i)引用了上层作用域的变量 i,构成闭包
a[i]中保存了10个闭包,各自保留了构成闭包时变量 i的值。


2个闭包栗子~

> var f=function(){
...  let i=0;
...  return function(){
.....  i=i+1
.....  return i
.....  }}()
undefined
> f()
1
> f()
2
> f()
3
> f()
4
> f()
5
> var fn;
undefined
> for(let i=-1;i<0;i++){
...     fn=function(){
.....         i=i+1
.....         return i
.....     }
... }
[Function]
> fn()
0
> fn()
1
> fn()
2
> fn()
3
>
ringa_lee

看了@同意并接受 的答案,现在我终于搞明白了,总结一下:

这个例子是很多ES6教程里面都有的,是和用var的for循环作对比,

var a = [];
for (var i = 0; i < 10; i++) {
    a[i] = function () {
        console.log(i);
    };
}
a[6](); //10
console.log(a[6]); // function () {console.log(i);};

我对这两个例子的理解是:

用let是ES6语法,for循环代码块构成一个作用域,里面的function形成闭包,function里面可以引用父作用域的变量,引用的是function被定义时的父作用域变量值,所以在每一次执行a[i] = function () { console.log(i);}时,function都保存了当时的i值。

而for使用var时,还是ES5的写法,for代码块没有形成作用域,所以里面的function不构成闭包,所以在每一次执行a[i] = function () { console.log(i);}时,并不会保存当时i的值,所以只有当a[i]()这个函数执行时,才会使i值变现,这时,function沿着作用域链查找i的值,父作用域就是window,i的值经过十次i++,已经是10,所以a[6]()会输出10

重要背景:一个知乎上关于闭包的问题(如何通俗易懂的解释javascript里面的‘闭包’?),在这个问题里,看到这样一句话之后,我如同被闪电劈中(这什么破比喻==),对于闭包概念的模糊一下子都消散了,就是这样一句话:
JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里。所以虽然我说了那么多,关键还是被被定义的作用域电光火石闪电劈中的一刹那

希望大家都能理解闭包( •̀∀•́ )

阿神

console.log(i) 应该是undefined才对吧。。。

高洛峰

你自己也说了a[6] = function(){console.log(i)},如果a[6]=10,那岂不是function(){console.log(i)}就是10? a[6]的值其实是这个匿名函数function(){console.log(i)},匿名函数也可以叫做函数表达式,换言之,这个表达式是a[6]的值。虽然表达式内部指示输出10,但是这不是a[6]。

伊谢尔伦
let是块作用域声明
经过for 循环后的a  有 10 个 闭包 成员 
a[6](); //6  ;  i = 6
console.log(a[6]); //  a[i] = function(){console.log(i)}  ;  i = 6 
console.log(i);   //   i is not defined   外包是无法访问到 let 内部成员的
伊谢尔伦

如果你把 let 换成 var 的话,你会神奇的发现 a[6]() 输出 10。
这里我感觉还是 i 的作用域决定的。
因为 i 的作用域仅仅是 for 循环内, 所以在函数中调用 i 的时候,需要形成一个闭包好让外部访问。
如果 换成 var,i 的作用域是这个 js 文件的全局,在函数中调用 i 的时候是可以找到这个变量的,无需形成闭包。
还有一个概念就是 var 的变量提升问题,你可以参考下这个。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号