一:从概念上理解:
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的变量对象(是个活动对象,函数执行完毕被销毁),而全局执行环境的变量对象始终存在。而闭包的情况下,情况又有所不同。
因就在于f1是f2的父函数,而f2被赋给了一个全局变量result,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
阮一峰的这个例子还是埋了一个坑的:这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。
前端小白,欢迎拍砖。
三.闭包举例的以及其作用
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); // 我们在这里传入参数来"闭包"变量
}
前端小白,欢迎拍砖。