关于javascript闭包的理解
2017-02-24 10:12
399 查看
一:从概念上理解:
1.闭包的定义:有权访问另一个访问另一个函数作用域中变量的函数。
2.实现方式:
在函数内部创建另一个函数。结合定义举例:b函数为了访问a函数的作用域中的变量:我们就将b函数创建在a函数当中。当然b函数通常是匿名函数的。
二:理解闭包的前提-----理解作用域链以及执行环境:
1.当一个函数被调用时候,会创建一个执行环境(每个执行环境都有一个表示变量的对象-----变量对象)以及相应的作用域链。内部函数可以访问外部函数的作用域,查找时候由内而外直到全局变量。ex:
var m = 3; function plus(a,b){ return a+b+m; } var c = plus(1,2 ); // 6
以上代码先定义了plus函数,再在全局作用域中调用,根据其作用域链,plus是可以访问到全局作用域中的m的。调用plus时候会创建一个包含a,b以及arguments的变量对象(是个活动对象,函数执行完毕被销毁),而全局执行环境的变量对象始终存在。而闭包的情况下,情况又有所不同。
三.闭包举例的以及其作用
1.访问函数的内部变量function f1(){ var n=999; function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999为了在全局作用域中访问到f1作用域中的n,将n在f1内部函数f2中返回。其实通常情况下不会向上面那样写,f2会作为一个匿名函数返回像下面这样:
return function(){ return n }2.让这些变量一直保存在内存中:
function f1(){ var n=999; nAdd=function(){n+=1} return function (){ alert(n); } } var result=f1(); result(); // 999 nAdd(); result(); // 1000可以看到第一次访问到了f1的内部变量,所以值为999,执行nAdd()后n的值为1000,并且函数执行完毕没有被销毁,所以再次执行f1,会得到n=1000;why?
因就在于f1是f2的父函数,而f2被赋给了一个全局变量result,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
阮一峰的这个例子还是埋了一个坑的:这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。
闭包引起的问题:
1.闭包使得其父函数的变量也会保存在内存中,如果不手动释放会一直占用内存。上例子的释放:result = null;实际上是解除了对匿名函数的引用。
2.对父函数中值得改变:
上例子中n值的改变。
理解闭包的经典的例子:
一:var name = "outer"; var object = { name : "inner", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()());关键点;this的指向是基于调用它的执行环境绑定的。所以结果是:outer。
var name = "outer"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()());关键点:首先将this赋给了一个成员变量that,因此,函数调用的作用域就限制在了obj对象中,其他的如前面代码段1的分析,最后结果输出的是"inner"
二:
for(var i = 0; i < 10; i++) { setTimeout(function() { console.log(i); }, 1000); }
结果是:10个10.而不是预期 的1-10.即使是把时间设置成0也是一样。可以理解成异步执行。
先给一个比较容易接受的解释:作用域链的配置机制引起的问题:闭包只能取得包含函数中任何变量的最后一个值;闭包保存的是整个的变量对象而不是某个值。
再来换一个解释:因为setTimeout中的匿名function没有将 i 作为参数传入来固定这个变量的值, 让其保留下来, 而是直接引用了外部作用域中的 i。.
如何得到1-10?
for (var i = 0; i < 10; i++) { (function(a) { // 变量 i 的值在传递到这个作用域时被复制给了 a, // 因此这个值就不会随外部变量而变化了 setTimeout(function() { console.log(a); }, 1000); })(i); // 我们在这里传入参数来"闭包"变量 }
前端小白,欢迎拍砖。
相关文章推荐
- 关于Javascript闭包的理解(二)
- 关于本人对javascript闭包的理解
- 关于javascript闭包的理解
- 关于Javascript闭包的理解
- 关于Javascript闭包的理解(三)
- 一些关于javascript闭包和this的理解
- 关于Javascript闭包的理解(一)
- 关于JavaScript闭包的理解
- 关于SCN的理解
- 关于VO、PO的理解
- 关于如何理解三层结构
- 关于ref,out,params参数的理解
- 关于CLR 2.0中托管泛型的理解
- 关于敏捷思维的一个连接&敏捷宣言理解
- 关于String和StringBulider的理解
- 关于编码的一些认识和理解(Kemin原创)
- 关于接口我的理解
- 关于ref,out,params参数的理解(粘贴的源代码,说明在注释里面)
- 关于scn的理解
- 关于DataRow和DataColumn的一点个人简单理解