新手,对闭包的理解不够,希望大佬们详细说下这段代码的运行过程,原理,机制等
阮一峰ES6中有将到这点
他书中的解释变量i是var命令声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i。也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,也就是 10。
如果使用let,声明的变量仅在块级作用域内有效,最后输出的是 6。
var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 6
上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
i是全局变量 调用a[6]()的时候去取i的值 这时候i早循环到10了跟下面一个道理
i
a[6]()
10
var i = 0; var a = function(){ console.log(i) } i=10; a()//10
调用的时候才去取值
函数内相关的值是在执行时确定的。所以执行时去确定i,没有传入i的值,会去外层作用域找,此时i已经在遍历完变成了10。跟闭包没多大关系。
无论i是几,a[i]();都是10,因为函数作用域变量的值是运行时确定的,不是定义时确定的,当函数执行的时候i已经++到10了。
var a = []; for (var i=0;i<10;i++) { a[i] = function () { // 这里的i具有迷惑意义,其实没什么作用 console.log(i); }; } //运行到这里i为10 a[6](); // 10 //到这里a[0]~a[10]都是function(){console.log(10)},由此得出结果。
1、function 并没形成闭包!你都能直接调用该函数,没闭包说法!2、es6之前,只存在两个作用域: 全局和function
所以i和function的执行环境同,且无闭包。待调用函数时,i = 10
这是函数运行中 执行上下文环境压栈入栈的过程。
你不断调用a[i], 都是从function(){ console.log(1) } 压栈,然后 function(){ console.log(2) } 压栈,然后function(){ console.log(3) }。一直到function(){ console.log(10) }压栈 http://www.cnblogs.com/wangfupeng1988/p/3992795.html 可以看看这个系列
去了解一下es6里面的let和var的区别就知道了
额,其实很简单,这个如果说要懂得应该就是函数的作用域了。当函数声明的时候就把函数作用域链的前几层也绑定好了。(因为你刚入门,我就少说点术语)那问题你中的的函数 function() {console.log(i) }为例子。怎么看他的作用域链呢,先不要看他函数的内部写的什么,先看他在哪里声明,声明时环境能访问到什么(例子中就是 i 和 a)。OK,为了让函数声明后能够访问到,JS会把这个能访问到i和a的环境赋予function,而function又被放在数组a中。OK,当上栗的循环结束后,我们得到一个包含10个函数的数组。当我们调用一个数组中的函数。如 a[6](). 当函数执行到要去读取i的时候,在函数的第一层中没有定义。那么JS就会去读取函数作用域的上一层(这个就是函数声明时保存的)关键来了,尽然函数一声明就要保存一个作用域链,而这些是放在内存中的。你想想这本来开销就大了,如果还保存着当时声明时的值得大小,如读者认为的 6 ,那对内存是极大的开销。所以JS选择保存的是内存的地址。而值是什么,就是执行时内存指向的值。这里是10. 为什么?因为声明函数时候,最后把i的值变为10.如果你理解的我说的,那么闭包也就懂了。
这段代码没有闭包 因为你的函数执行了的时候已经循环完毕了 i已经加到了10 所以这时不管你调用的是a[]多少的函数 返回的都是10如要取到当前的值, 可以使用闭包for ( var i=0; i<10; i++ ) {
(function(i){ a[i] = function () { console.log(i) } })(i)
}这里有一个匿名自执行的函数 在i循环的时候就取到了当前的i的值
这个是考的var的作用域,你可以这样试一下,应该就能明白了
var a = [] console.log(index) // undifined console.log(b) // b is not defined for (var index = 0; index < 10; index++) { a[index] = function() { // 此时无论这个方法内怎么写都无所谓,不执行的 console.log(index) } } a[6]() // 这时执行方法,而index已经for完成了
http://www.cnblogs.com/wangfu... 去看看王福朋关于闭包的一系列解读吧。适合新手,简单易懂。
js中没有代码块的限制, 所以变量i就是一个全局变量
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
暂无简介
文章 0 评论 0
接受
发布评论
评论(13)
阮一峰ES6中有将到这点
他书中的解释
变量i是var命令声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i。也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,也就是 10。
如果使用let,声明的变量仅在块级作用域内有效,最后输出的是 6。
上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
i
是全局变量 调用a[6]()
的时候去取i
的值 这时候i
早循环到10
了跟下面一个道理
调用的时候才去取值
函数内相关的值是在执行时确定的。
所以执行时去确定i,没有传入i的值,会去外层作用域找,此时i已经在遍历完变成了10。
跟闭包没多大关系。
无论i是几,a[i]();都是10,因为函数作用域变量的值是运行时确定的,不是定义时确定的,当函数执行的时候i已经++到10了。
1、function 并没形成闭包!你都能直接调用该函数,没闭包说法!
2、es6之前,只存在两个作用域: 全局和function
所以i和function的执行环境同,且无闭包。待调用函数时,i = 10
这是函数运行中 执行上下文环境压栈入栈的过程。
去了解一下es6里面的let和var的区别就知道了
额,其实很简单,这个如果说要懂得应该就是函数的作用域了。当函数声明的时候就把函数作用域链的前几层也绑定好了。(因为你刚入门,我就少说点术语)
那问题你中的的函数 function() {console.log(i) }为例子。怎么看他的作用域链呢,先不要看他函数的内部写的什么,先看他在哪里声明,声明时环境能访问到什么(例子中就是 i 和 a)。OK,为了让函数声明后能够访问到,JS会把这个能访问到i和a的环境赋予function,而function又被放在数组a中。
OK,当上栗的循环结束后,我们得到一个包含10个函数的数组。
当我们调用一个数组中的函数。如 a[6](). 当函数执行到要去读取i的时候,在函数的第一层中没有定义。那么JS就会去读取函数作用域的上一层(这个就是函数声明时保存的)
关键来了,尽然函数一声明就要保存一个作用域链,而这些是放在内存中的。你想想这本来开销就大了,如果还保存着当时声明时的值得大小,如读者认为的 6 ,那对内存是极大的开销。所以JS选择保存的是内存的地址。而值是什么,就是执行时内存指向的值。这里是10. 为什么?因为声明函数时候,最后把i的值变为10.
如果你理解的我说的,那么闭包也就懂了。
这段代码没有闭包 因为你的函数执行了的时候已经循环完毕了 i已经加到了10 所以这时不管你调用的是a[]多少的函数 返回的都是10
如要取到当前的值, 可以使用闭包
for ( var i=0; i<10; i++ ) {
}
这里有一个匿名自执行的函数 在i循环的时候就取到了当前的i的值
这个是考的var的作用域,你可以这样试一下,应该就能明白了
http://www.cnblogs.com/wangfu... 去看看王福朋关于闭包的一系列解读吧。适合新手,简单易懂。
js中没有代码块的限制, 所以变量i就是一个全局变量