精通js? 如果你能把一个for循环说得通俗易懂。。。
发布于 2 个月前 作者 yuelau 1004 次浏览 来自 问答
let 
	 arr = [],
     arr2 = [],
	 arr3 = [];

		//正常写法
		for (var i=0; i<10; i++) {
			arr[i] = function () {
				console.log(i)
			}
		}

		console.log(arr[5]())		//10

		//闭包
		for (var i=0; i<10; i++) {
			arr2[i] = function (num) {
				return function () {
					console.log(num)
				}
			}(i)
		}

		console.log(arr2[5]())		//5
		
		//es6
		for (let i=0; i<10; i++) {
			arr3[i] = function () {
				console.log(i)
			}
		}

		console.log(arr3[5]())	//5

** 使用了es6的let声明,使用较新的chrome浏览器查看不会报错 **

7 回复

我是这样理解的。 首先第一个,var声明的变量i,在整个模块里有效,也就是在你的这份代码里是全局的,虽然存进数组中的i在存入那一刻是对应的值,但最后i变成了10,所以数组中任何一个元素会打印出10。 而let声明的变量i是块作用域,在每次循环的时候生成新的变量,所以你打印出来的数组的每个元素是不同的。 闭包中的num是形参,打印的时候和i没有关系,是num的值。

来自酷炫的 CNodeMD

for里面的var改成let

@AviorAlong ,很专业。 我基础不太好,理解不那么透彻。 于是本地debug分析,打印结果如下图: //正常写法 1.png //闭包写法 2.png //es6写法 3.png

一些个人见解: 每个函数调用进行打印变量时,都是一个变量查找的过程,先在自身的作用域查找这个变量,没有依次向上查找。 //正常写法 i泄漏为全局变量,归并到了全局作用域下,函数调用,其实查找的是window.i 。循环结束时window.i值是10,于是结果是10

//闭包写法 先查找闭包的num形参(理解为变量也可以),查找到了,就停止了,打印值

//es6写法 与闭包的原理类似,只是将闭包换成了块作用域,两者都是创建局部作用域的方式

var 存在变量提升…

你理解的没错。 var指令以及对console.log的调用使得第一个变量i的作用域提升到了全局,这就是var的作用域提升机制。 这也就是为什么尽量不要再用var关键字了,虽然围绕var有很多奇淫技巧,但是很容易造成代码可读性降低和未知BUG的风险。 ES6的let和const对BUG风险控制非常有好处。

这个程序主旨再说明,变量作用域,以及变量污染;

{
		 var x =1;
		 let  y = 2;
}
{
		console.log(x);//正常打印
		console.log(y);//执行异常     ReferenceError: y is not defined
}

node以及es6 不建议用 var

bad
var x=0;
good
let x = 0;
better
const x = 0;
回到顶部