在ES6中新加了快作用域的概念(C语言就有,作为类c语言的js,当然应该加上),算是很好理解。
{ let i; } console.log(i);// i is not defined
在代码块当中使用新的作用域。
问题在于for语句
let arr=[]; for(let i=0;i<5;i++){ arr[i]=function(){ console.log(i); }; }
许多的讲解并没有特别说明它的作用域是怎么看的,似乎是自然而然的事情。
然而对于以前c没专心学,真正会的也就类似PHP,javascript的无块作用域的孩子就觉得疑惑了。
我的错误理解1:
let arr = []; (function(){//作用域直接包含整个for循环?wrong for (var i = 0; i < 5; i++) { arr[i] = function () { console.log(i); }; } })();
我的错误理解2:
let arr = []; for (var i = 0; i < 5; i++) { (function () {//作用域包含单次循环?wrong arr[i] = function () { console.log(i); }; })(); }
测试结果都说明自己的理解是有误的,找资料的时候,这里都一笔被带过了(可能因为各位作者都用过块作用域的吧)。
于是想到babel既然是ES6转ES5,理解是正确的,那么可以找它帮忙。
方法,使用babel转码加深特性的理解,
转码前:
let arr=[]; for(let i=0;i<5;i++){ arr[i]=function(){ console.log(i); }; i++; } console.log(i);//i is undefined arr[0]();
转码后:
"use strict"; var arr = []; var _loop = function _loop(_i2) { arr[_i2] = function () { console.log(_i2); }; _i2++; _i = _i2; }; for (var _i = 0; _i < 5; _i++) { _loop(_i); } console.log(i); //i is undefined arr[0]();
通过babel转码后就可以清晰的看出来了:
1、作用域是分成两部分的,在整个for循环外层相当于有一个作用域,这里babel使用变量 _i 来区别 i 变量,等价于一个作用域,在理解上可以这样理解,
let arr = []; for (let i = 0, len = 5; i < 5; i++) { arr[i] = function () { console.log(i); }; } console.log(i); arr[0](); "use strict"; var arr = []; var _loop = function _loop(_i) { arr[_i] = function () { console.log(_i); }; }; (function () { for (var i = 0; i < 5; i++) { _loop(i); } })(); console.log(i); //i is undefined arr[0](); "use strict"; var arr = []; (function () {//等价于for循环外层作用域,babel中使用变量别名来优化 var _loop = function _loop(_i2) { arr[_i2] = function () { console.log(_i2); }; _i2++; i = _i2; }; for (var i = 0; i < 5; i++) { _loop(i); } })(); console.log(i); //i is undefined arr[0]();
2、每个单次循环也是一个作用域,代码中的_loop,即是用函数作用域来模拟块作用域。
3、在单次循环中注入了for语句中声明的i变量,并且在一次循环后,将i变量赋值回来(_loop代码中i=_i2)。
运行结果是一样,但是却觉得我的理解很有问题,通常越强大的规则通常是越简单的,是否有更准确的解释呢?求不吝相告