闭包
*指有权访问另一个函数作用域中的变量的函数,常见的创建闭包的方式就是在一个函数内部创建另一个函数
闭包与变量
因为闭包保存的是整个变量对象,而不是某个特殊的变量,所以闭包只能取得函数中任意变量的最后一个值,我们可以使用匿名函数重新在函数内复制一个仅存在在该匿名函数内的变量,与之前的变量相互独立出来,就可以使每个函数返回的变量值不相同
function foo(){
var result = new Array();
for (var i =0; i<10;i++){
result[i] = function(){
return i;
};
}
return result
}
此函数数组中每一个函数返回的值都是10,因为他们的保存的i是同一个,当后面的i发生改变的时候,前面所保存的i也会同时发生改变
为了解决这个问题,我们可以创建一个匿名函数强制让闭包返回的变量值不一样
function foo() {
var result = new Array();
for (var i = 0; i < 10; i++) {
result[i] = function (num) {
return function (num) {
return num
};
}(i);
}
return result
}
因为函数的参数是按值传递的,相当于闭包内部的函数通过值传递,使用num复制了一份i的值,这样后面再执行i++改变i的值时,num的值不会被改变,还是最初的i值,这样就记录下每一次i的值
闭包内部的this
下面这个调用obj.getName()()时返回的是 “the window”
var name = "the window";
var obj = {
name:"the Object",
getName:function(){
return function(){
return this.name;
};
}
}
console.log(obj.getName()())//"the window"
为什么呢?我们可以简单来看:将obj.getName()()拆开,
- 先执行obj.getName(),此时得到的是一个函数
function(){return this.name; };
- 那执行obj.getName()()这个函数也就是在全局作用下执行 function(){return this.name; }这个匿名函数了,所以this指向了全局
所以为了让闭包访问包含函数内的this,我们可以给设置一个变量指向包含函数的this,如下所示:
var name = "the window";
var obj = {
name:"the Object",
getName:function(){
var that = this
return function(){
return that.name;
};
}
}
console.log(obj.getName()())
此时的执行结果就是“the Object”
内存泄露
使用闭包很容易导致内存泄露,即如果闭包的作用域链中保存着一个HTML元素,那么就意味着该元素将无法被销毁
function forStorage (){
var element = document.getElementById("someElement");
element.onclick = function () {
alert(element.id);
}
}
因为匿名函数保存了一个对 forStorage 函数的引用,就会导致无法减少element的应用数,也就是说只有匿名函数存在,element的引用数至少也是1,即所占用的内存就永远不会被回收,为了解决这个问题我们可以定义一个变量保存element.id,并且在执行完匿名函数后,将element=null来解除引用,确保可以正常回收
function forStorage() {
var element = document.getElementById("someElement");
var id = element.id;
element.onclick = function () {
alert(id);
};
element = null;
}