整理一下对闭包的理解
var fn = null; //定义全局变量 fn
function foo() {
var a = 2;
function innerFoo() { //定义内部函数 innerFoo
console.log(a);
}
fn = innerFoo; //将 innerFoo 赋值给全局变量 fn
}
foo(); // undefined
fn(); // 2
为什么要用闭包呢?
- 我们想要在当前作用域之外,访问函数 foo 内部的变量 a。
- 当函数 foo 执行完毕后,生命周期结束,其函数的上下文失去引用,占用的内存空间很快就会被垃圾回收期释放。闭包会阻止这一过程。
- 尽可能少的全局变量。
- 在 JavaScript 中内部函数可以访问外部函数的上下文。
什么是闭包呢?
当函数(内部函数)可以记住并访问所在的作用域(全局作用域除外)时,就产生了闭包,使函数在当前作用域外执行。
在例文代码中闭包是什么呢?
foo 是闭包(Chrome 浏览器认为),而不是之前一直认为的 innerFoo 。
闭包的应用
延迟函数
、柯里化
、模块
以延迟函数为例:
function fn() {
console.log("hello world");
}
var timer = setTimeout(fn,1000);
timer;
console_2
执行 timer 时,返回这个 setTimeout 的 ID,表明 setTimeout 函数本身已经执行完毕。一秒钟之后,fn (保存在 setTimeout 的变量对象中)才会执行。
按理来说一秒后 setTimeout 执行结束后,fn 也就不存在了,但是事实上依旧输出了 hello world。
这正是由于闭包。setTimeout 保留了 fn 的引用,使 fn 没有在其执行完毕后被垃圾收集器回收。由此 setTimeout 执行结束后一秒,我们仍能使用 fn 。
带来的问题-内存泄露
-
闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题。
-
由于
IE
的js
对象和DOM
对象使用不同的垃圾收集方法,因此闭包在IE中会导致内存泄露问题,也就是无法销毁驻留在内存中的元素。 -
解决思路:在函数之前,将不使用的局部变量全部删除。
-
赋值 null,解除引用
function closure(){
var element = document.getElementById('someElement');//element用完之后一直驻留在内存中
element.onclick = function () {
alert('element.id');//这里用element导致内存泄露
};
}
closure();
//解决
function closure(){
var element = document.getElementById('someElement');
var id = element.id; //将element.id保存在一个变量中,然后在内部函数中引用,消除对该变量的循环引用。
element.onclick = function () {
alert('id');
};
element = null; //将element解除引用来避免内存泄露
}
- 在外面包一层匿名自执行函数
(function () {
...//闭包
})();
//好处:不会污染全局变量,在匿名函数执行完了里面的的变量就释放掉了
网友评论