1. 闭包的概念
通俗理解:闭包是能够读取其他函数内部变量的函数;
闭包 = 内层函数 + 引用的外层的函数变量 ; 即内层函数引用外层函数的变量就构成了闭包。
闭包作用:闭包可以保护函数的私有变量不受外部的干扰,将上级作用域的引用保存下来,实现方法和属性的私有化。
常见的创建闭包的方式:在一个函数内部嵌套函数,内部函数引用外层函数中定义的变量;如下图所示:
//闭包 1: 2-5 行构成一个闭包
1 function outer() {
2 let name = 'andy';
3 return function() {
4 console.log(name);
5 }
6 } outer()();
//闭包 2: 2-6 行构成一个闭包
1 function outer() {
2 let name = 'andy';
3 function inner() {
4 console.log(name);
5 }
6 inner();
7 }
8 outer();
2. 闭包的优缺点
优点:
- 避免全局污染;
- 变量长期存储在内存中; 在函数体内,随着函数每一次执行完毕,函数内部定义的对象(如果没有被闭包函数引用),会被销毁;如果被闭包引用,则被保留下来。所以闭包的存在,导致变量不会被销毁,保留了下来,从而长期存储在内存当中;
缺点:
- 内存泄漏(消耗):应用程序中不再用到的内存,由于某些原因,无法及时释放,导致了内存的泄漏。
闭包的存在,使得某些变量不能被及时销毁,内存也无法及时释放,也就导致了内存的泄漏。但是闭包存在,不一定就会导致内存泄漏。 闭包导致内存的泄漏只存在 IE 浏览器中,其他浏览器中不会导致内存的泄漏。 - 常驻内存,增加内存使用量:这个内存浪费不仅因为它常驻内存,更重要的是,对闭包的使用不当,会造成无效内存的产生;
- 性能问题:使用闭包时,会涉及跨作用域的访问,每次访问都会导致性能损失;
3. 闭包应用场景
- 实现模块化;
- 实现变量的私有封装;
- 实现迭代器;
4. 当 this 碰上闭包
在非严格模式下,一般来说,闭包中的 this 指向 window,严格模式,闭包中的 this 为 undefined;
var uname = "window";
var object = {
uname : "object",
fun: function() {
console.log(this.uname); // object 由 Object对象调用,this 指向 Object
return function() {
console.log(this.uname); //window 闭包 普通函数调用,指向 window
}
}
}
object.fun()();
5. 闭包的销毁
在模块或应用执行完成后,将内层函数赋值为 null 即可,如 inner( ) = null;
6. 闭包的常见理解误区
- 闭包一定要有 return 将函数返回 (错);
下图的闭包不包含 return,可见 return 不是构成闭包的必要条件。
//闭包 2: 2-6 行构成一个闭包
1 function outer() {
2 let name = 'andy';
3 function inner() {
4 console.log(name);
5 }
6 inner();
7 }
8 outer();
- 闭包一定导致内存泄漏 (错)
只有 IE 浏览器中的闭包才有可能导致内存的泄漏,其他浏览器不会。闭包可能导致内存的泄漏,不是一定会导致内存泄漏。
7. 调试器查看闭包
谷歌浏览器为例:
- 打断点,页面刷新
- 点击单步按钮,查看代码执行顺序。当代码运行到第 14 行时,显示 Closure(outer)即闭包。
参考文章推荐: