宝哥软件园

JavaScript闭包和范围链案例分析

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

本文展示了JavaScript闭包和范围链。分享给大家参考,如下:

闭包定义

闭包指的是可以访问另一个函数范围内的变量的函数。创建闭包的常用方法是在函数A内部创建另一个函数B,那么函数B就是一个闭包,可以访问函数A范围内的所有变量。

JavaScript的闭包与作用域链息息相关,所以本文可以对JavaScript的作用域链进行对比分析,肯定会对JavaScript的闭包和作用域链有更深的理解。

我们仍然以createComparisonFunction为例来分析闭包。

//step1:定义createComparisonFunction createComparisonFunction(property name){返回函数(object1,object 2){ var value 1=object 1[property name];var value 2=object 2[PrOperty name];if(value 1 value 2){ return-1;} else if(value 1 value 2){ return 1;} else { return 0;} };}//step2:调用createComparisonFunctionvar compareName=createComparisonFunction(' name ');var compare age=createComparisonFunction(' age ');//step3:调用compare var object 1={ name : ' Nicholas ',age : 25 };var object2={ name : 'Greg ',age : 27 };var result1=compareName(object1,object 2);//1 var result 2=compare age(object 1,object 2);//-1//step4:取消对recycle memorycompareName=null的引用闭包;compareAge=null在这个例子中,匿名函数(object1,object2)是一个闭包,可以访问createComparisonFunction范围内的所有变量。自然,它还包含propertyName属性。由于propertyName参数不同,比较的属性也不同,所以函数执行结果也不同。

闭包和变量

从JavaScript的作用域链我们知道,JavaScript使用作用域链来确定函数执行环境的作用域,这就导致了一个明显的副作用,那就是闭包只能得到函数中任意变量的最后一个值。闭包是指外部函数的活动对象访问活动对象中的所有变量,因此这些变量的值在外部函数执行过程中可能会发生变化,但外部函数的活动对象在外部函数执行后不会发生变化。因此,闭包通过作用域链访问外部函数活动对象的所有变量,只能是外部函数执行后最后保存的值。我们用一个例子来说明这种副作用。

函数createFunctions(){ var result=new Array();for(var I=0;i 10i ){结果[i]=函数(){返回I;};}返回结果;} var functions=createFunctions();for(var I=0;函数长度;I){ console . log(functions[I]());}输出结果是

10 10 10 10 10 10 10 10 10 10

表面上看起来每个函数都应该返回自己的索引值,但实际上每个函数都返回10。createFunctions的活动对象存储在每个函数的作用域链中,所以它们都引用了createFunctions活动对象中的变量I。在createFunctions返回之后,变量I的值是10。此时,每个函数都引用存储变量I的同一个变量对象,因此每个函数内部的I值为10。

让我们以调用函数[3]()为例来说明:

闭包函数的函数对象的作用域链引用的createFunctions的活动对象中保留的变量I的值是10。因此,无论是functions[3]()还是functions[5](),其运行时上下文的作用域链引用的createFunctions的活动对象都是同一个活动对象,活动对象中保留的变量I的值为10。

如何避免这种情况?我们可以通过创建另一个匿名函数来使闭包按预期运行。

函数createFunctions(){ var result=new Array();for(var I=0;i 10I){ result[I]=function(num){ return function(){ return num;} }(I);}返回结果;} var functions=createFunctions();for(var I=0;函数长度;I){ console . log(functions[I]());}输出结果是

0 1 2 3 4 5 6 7 8 9

这个代码片段和之前的代码的区别在于,立即调用了一个匿名函数(num),这样闭包函数()引用了function(num)的活动对象,访问的是活动对象中的变量num,而不是createFunctions活动对象中的变量I,而num调用函数(num)则立即具有索引值0,1,2…9。

让我们仍然以调用函数[3]()为例来说明:

执行createFunctions函数时,会依次调用function (0)、function (1) … function (9)生成function(num)的10个活动对象,即function (0)、function (1) … function (9)和result[0],这10个匿名函数对象的作用域链,result[1] … result[9],分别是指10个function(num)的活动对象,变量num的值也是0,1 … 9。

因此,无论是functions[3]()createFunctions[5](),其运行时上下文的作用域链都会引用function(num)的活动对象,如function(3)或function(5),它们是不同的活动对象,保留的num值分别为3和5。

更多对JavaScript相关内容感兴趣的读者可以查看本网站专题:《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》、《JavaScript数学运算用法总结》、0103010

希望本文对JavaScript编程有所帮助。

更多资讯
游戏推荐
更多+