JavaScript闭包与作用域链实例分析
本文实例讲述了JavaScript闭包与作用域链。分享给大家供大家参考,具体如下
闭包定义
闭包指的是有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数A内部创建另一个函数B,那么函数B就是一个闭包,可以访问函数A作用域中的所有变量。
JavaScript的闭包与作用域链密不可分,本文可以和相对照分析,一定可以对JavaScript的闭包和作用域链有更深的理解。
狼蚁网站SEO优化我们仍然以createComparisonFunction为例进行闭包的分析。
//step1: define createComparisonFunction function createComparisonFunction(propertyName){ return function(object1, object2){ var value1 = object1[propertyName]; var value2 = object2[propertyName]; if (value1 < value2) { return -1; } else if (value1 > value2) { return 1; } else { return 0; } }; } //step2: call createComparisonFunction var pareName = createComparisonFunction("name"); var pareAge = createComparisonFunction("age"); //step3: call pare var object1 = { name : "Nicholas", age : 25 }; var object2 = { name : "Greg", age : 27 }; var result1 = pareName(object1, object2); // 1 var result2 = pareAge(object1, object2); // -1 //step4: dereference closure for recycle memory pareName = null; pareAge = null;
在这个例子中,匿名函数function(object1, object2)是一个闭包,能访问createComparisonFunction作用域里的所有变量,自然也包含propertyName属性, 因为propertyName参数的不同,导致比较的属性也有所不同,从而函数执行结果也有不同。
闭包与变量
从中,我们了解到JavaScript是通过作用域链来确定函数执行环境的作用域的,这种机制会引出一个值得注意的副作用,即闭包只能取得包含函数中任何变量的一个值。闭包是通过引用外部函数的活动对象来访问该活动对象中的所有变量,在外部函数执行过程中,这些变量的值可能会变化,在外部函数执行完毕之后,外部函数的活动对象便不会再改变,在执行闭包的时候,闭包通过作用域链访问到外部函数的活动对象中的所有变量都只可能是在外部函数执行完毕之后,外部函数的活动对象中所保存的值。我们通过一个例子来说明这种副作用。
function createFunctions(){ var result = new Array(); for (var i = 0; i < 10; i++){ result[i] = function(){ return i; }; } return result; } var functions = createFunctions(); for(var i = 0; i < functions.length; 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。
我们以调用functions[3]()
为例,图解一下
Closure函数的Function对象的作用域链引用的createFunctions的活动对象中保留的变量i的值为10。所以不管是functions[3]()
还是functions[5]()
,其运行时上下文的作用域链引用的createFunctions的活动对象都是同一个活动对象,该活动对象中保留的变量i的值是10。
如何避免这种局面?我们可以通过创建另一个匿名函数让闭包的行为符合预期。
function createFunctions(){ var result = new Array(); for (var i = 0; i < 10; i++){ result[i] = function(num){ return function(){ return num; } }(i); } return result; } var functions = createFunctions(); for(var i = 0; i < functions.length; i++){ console.log(functions[i]()); }
输出的结果是
0 1 2 3 4 5 6 7 8 9
这个代码片段与前面的代码的区别在于立即调用了一个匿名函数function(num),使得闭包function()引用的是function(num)的活动对象,访问的是该活动对象中的变量num而不是createFunctions活动对象中的变量i,而在立即调用function(num)的num是索引值0,1,2…9。
我们仍旧以调用functions[3]()
为例,图解一下
在执行createFunctions函数的时候,会依次调用function(0), function(1) … function(9), 生成function(0), function(1) … function(9)这10个function(num)的活动对象,而result[0], result[1] … result[9]这10个匿名函数对象的作用域链分别引用这10个function(num)的活动对象,而其中的变量num的值也对应的为0, 1 … 9。
所以不管是functions[3]()
还是functions[5]()
,其运行时上下文的作用域链都会引用在执行createFunctions函数时候所执行的function(3)或者function(5)这些function(num)函数的活动对象,这些活动对象都是不同的活动对象,其中保留的num值分别为3, 5。
更多关于JavaScript相关内容感兴趣的读者可查看本站专题《》、《》、《》、《》及《》
希望本文所述对大家JavaScript程序设计有所帮助。
编程语言
- 如何快速学会编程 如何快速学会ug编程
- 免费学编程的app 推荐12个免费学编程的好网站
- 电脑怎么编程:电脑怎么编程网咯游戏菜单图标
- 如何写代码新手教学 如何写代码新手教学手机
- 基础编程入门教程视频 基础编程入门教程视频华
- 编程演示:编程演示浦丰投针过程
- 乐高编程加盟 乐高积木编程加盟
- 跟我学plc编程 plc编程自学入门视频教程
- ug编程成航林总 ug编程实战视频
- 孩子学编程的好处和坏处
- 初学者学编程该从哪里开始 新手学编程从哪里入
- 慢走丝编程 慢走丝编程难学吗
- 国内十强少儿编程机构 中国少儿编程机构十强有
- 成人计算机速成培训班 成人计算机速成培训班办
- 孩子学编程网上课程哪家好 儿童学编程比较好的
- 代码编程教学入门软件 代码编程教程