您的位置:首页 > Web前端 > JavaScript

JavaScript闭包-闭包中的变量和this对象

2016-10-21 16:51 281 查看
在JavaScript中作用域链的机制会引发一些副作用:闭包只能够获取包含函数中任何变量的最后一个值。在使用闭包的时候,我们一定要注意变量值的问题,因为这是经常会出错的地方。

下面我们以一个非常极端的例子来说明这个问题,在实际开发中我们一般不会这样编写代码。这个例子的代码如下:

执行上面的代码,我们预期会在页面中打印出0-9,但是实际上会打印10个10。我们来分析一下这段代码:实现代码中创建了一个函数fn1,在函数中创建了一个数组对象,并通过一个for循环为数组赋值,循环了10次,每一次往数组中填充一个匿名函数返回值,最后返回数组对象。接着获取fn1函数的引用,然后通过循环在页面中输出数组中的值。

上面的程序的作用域链内存模型如下图所示:



从图中我们可以看到,每次在fn1函数中的循环都会产生一个匿名函数,它们有各自的作用域链,它们的作用域链的高位都指向全局作用域,中间位指向外层的fn1作用域,低位才是指向自己的作用域。

当函数fn1执行完毕之后,fn1作用域中的属性
i
的值为10,此时GC开始回收fn1,但是它发现有匿名函数指向fn1的作用域,所以fn1的作用域不会被回收。

在匿名函数执行的时候,它在自己的空间中查找属性
i
,但是没有找到,于是就到它上级的fn1作用域中去查找,此时,fn1作用域中的i值为10,所以所以匿名函数都会获得相同的i值:10。

解决这个问题的方法是在匿名函数中再返回一个匿名函数,并通过一个变量来保存当前的数值。代码如下:

此时,
num
的值保存在每一个匿名函数自己的作用域中,并且数值刚好等于每次循环的索引值。这样,在每次调用匿名函数的时候,它会在自己的空间中找到
num
属性,并且这些
num
的值都是不同的,同时也不会再到fn1函数作用域中去查找
i
属性。

上面的代码会产生20个匿名函数的作用域,如果代码中不是简单的返回值,而是一些更复杂的操作,将会占用大量的内存空间。

 闭包中的this对象


在闭包中使用
this
对象也会出现一些意想不到的问题。
this
对象是在运行时基于函数的执行环境绑定的:对于全局函数,
this
对象就是
window
,而当函数在作为某个对象的方法被调用时,
this
就是那个对象。在匿名函数中,
this
对象通常是指向
window
的。我们来看下面的例子:

上面的代码中,我们调用
person
对象的
say()
方法时,打印出来的不是
person
对象的名字,而是全局的名字“window”。当完成
person.say()
之后,该函数调用完毕,在该函数调用结束之前,
this
是在指向
person
的,但是在调用匿名函数的时候,
this
就指向
window
了,所以得到的结果是“window”。

解决这个问题的方法是在
say()
方法中将
this
引用赋值给一个临时变量。代码如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: