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

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

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

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

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

上一节我们学习了“JavaScript面向对象-原型的内存模型”,介绍了DOM扩展的一些知识,今天主要学习JavaScript闭包-闭包中的变量和this对象。

varname="window";varperson={name:"Leon",age:22,say:function{returnthis.name;}}}console.info;//控制台输出:window
varname="window";varperson={name:"Leon",age:22,say:function(){varthat=this;returnfunction(){returnthat.name;}}}console.info;//控制台输出:Leon

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

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

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

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

functionfn1;//变量i保存在fn1作用域中for{arr[i]=function(){returni;}}returnarr;}varvalues=fn1();for(vari=0;i");}

返回javascript教程主目录>>

闭包中的this对象

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

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

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

functionfn1;for{arr[i]=function{returnnum;}};}returnarr;}varvalues=fn1();for(vari=0;i");}

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

相关文章

网站地图xml地图