关于javascript闭包的理解

来源:互联网 发布:vb.net 控件数组 编辑:程序博客网 时间:2024/06/05 11:23

一:从概念上理解:

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); // 我们在这里传入参数来"闭包"变量   }

前端小白,欢迎拍砖。
















1 0