宝哥软件园

详细解释JavaScript关闭机制和示例代码

编辑:宝哥软件园 来源:互联网 时间:2021-09-07

首先要区分两个概念,一个是匿名函数,一个是闭包。

匿名函数是在没有给定函数名的情况下创建的。通常,包含函数表达式是定义一个匿名函数,然后将该函数赋给一个变量,该变量相当于函数的函数名,例如:

var SayHi=function(){ alert(' Hi ');};//注意这个分号sayHi();//Call函数另一个常见的匿名函数是回调函数,常用于JQuery:

$('p ')。click(function(){ alert(' click ');});此外,还有匿名函数作为函数的返回值:

函数say namewithage(age){ return function(person){ if(person . age==age){ return person . name;}}}那么,闭包呢?所谓闭包其实就是一个函数,这个函数的特殊之处在于它有权访问其他函数范围内的变量。

从定义中我们发现,其实在上面的匿名函数例子中,就有这样一个闭包。在最后一个示例中,匿名函数访问函数sayNameWithAge的参数age,因此作为返回值的匿名函数是闭包。

为了彻底理解闭包,我们必须理解函数调用的整个机制,这是从范围链的相关知识来解释的。

首先看下面的例子:

函数sayName(名称){ alert(名称);} say name(' Jack ');调用上述函数sayName时,会创建相应的执行环境和范围链,如下图所示:

调用sayName函数时,会创建对应的作用域链,作用域包含两个指向两个对象的引用,其中一个是全局变量对象,在创建函数时创建,在调用函数时只复制到作用域链;另一个是函数的活动对象,它是在调用函数时创建的。

当您访问函数中的变量时,您将使用相应的名称搜索变量的范围。

当函数执行时,函数的活动对象将被销毁,而全局变量对象将始终存储在内存中。

但是,以上都是普通函数的情况,对于闭包来说,又是另外一种情况:

以上面的sayNameWithAge函数为例:

函数say namewithage(age){ return function(person){ if(person . age==age){ return person . name;} } }//创建函数var sayName=saynamewithege(18);//调用函数var name=say name({ name : ' jack ',age :18 });//取消对匿名函数sayName=null的引用;调用上面的sayName函数时,生成的作用域链如下:

当匿名函数被返回时,其作用域链被创建,并包括外部函数的活动对象和全局变量对象,这样匿名函数就可以访问sayNameWithAge函数中定义的所有变量,即闭包。

这个闭包有一个问题,就是在执行sayNameWithAge函数时(JS的垃圾处理机制大多是标签清除),它的活动对象被闭包引用,所以不会被破坏。只有当匿名函数被销毁时,sayNameWithAge的活动对象才会被销毁,所以上面最后一行取消了对匿名函数的引用,不仅是为了销毁闭包的对象,也是为了销毁外部函数的活动对象。因此,请谨慎使用闭包!

关于闭包需要注意的另一点是,其他函数的变量是在闭包中访问的。事实上,在闭包的范围链中有对其他函数的活动对象的引用,但是这些变量存储在闭包本身的活动对象中。请看下面的例子:

函数outer(){ var result=new Array();for(var I=0;i5;i ){结果[i]=函数(){返回I;};}返回结果;}假设由outer返回的数组的每一项中的值应该与其下标一致。然而,最终的结果是每个项目的值是5。不难想象,在上面所有闭包的作用域链中,有一个指向outer的活动对象中的参数I的引用,它指向同一个对象。

当外部函数完成执行时,I的值为5。也就是说,在所有闭包中访问I时获得的值是5

然后,我们可以通过另一种方法达到预期的效果:

函数outer(){ var result=new Array();for(var I=0;i5;I){ result[I]=(function(index){ return index;})(I);}返回结果;}在这里,我们为匿名函数定义了一个参数索引,并在每个循环中立即调用这个函数,将I的当前值复制到参数索引中(注意JS是按值传递的),并将返回的索引赋给result。

另外,闭包中需要注意的另一个问题是这个对象。

当函数运行时,该对象基于函数的执行环境绑定在JS中。匿名函数的执行环境是全局的,也就是说,在匿名函数中,这个对象通常指向window。

var name=' Tomvar person={ name : 'Jack ',say name : function(){ return(function(){ return this . name;})();} } person . SayName();//Tom在上面的闭包中访问this.name,其中这个对象没有得到自己或者这个人的this对象,而是指向window。

如果需要在闭包中访问外部函数的这个对象,可以在外部函数中定义一个变量,并将这个对象传递给这个变量。

var name=' Tomvar person={ name : 'Jack ',say name : function(){ var self=this;return(function(){ return self . name;})();} } person . SayName();//Jack感谢阅读,希望对大家有所帮助,感谢大家对本站的支持!

更多资讯
游戏推荐
更多+