读完阮一峰大佬写的《学习Javascript闭包(Closure)》发现之前自己对闭包理解的还是比较片面。闭包作为JS的难重点,理解和使用闭包是非常重要的。这篇博客记录一下“豁然开朗”的感受,和对闭包粗俗的理解,或许对你有帮助。(下文有内容引用)
闭包的概念
-
作用域
理解闭包,首先要理解JS的作用域。
//1.函数内部可以直接读取全局变量
var n=1;
function f1(){
alert(n);
}
f1(); // 1
//2.函数外部无法读取函数内部的局部变量
function f1(){
var n=1;
//注意:在函数内部定义“局部变量”需要用var来定义,直接 n=1 是定义了全局变量
}
alert(n); // error
-
闭包的概念
闭包,就是能够读取其他函数内部变量的函数。
Javascript语言特有的"链式作用域"结构决定了只有函数内部的子函数能够访问函数内部的变量,外部则不可以。
而闭包就是这座函数外部能够访问到函数内部的桥梁。
闭包的两大用处
-
读取函数内部的变量
闭包使用方式如下:1.外部无法访问函数f1()的局部变量 n,函数f2()作为函数f1()的子函数可以读取到n的值
2.将函数f2()作为函数f1()的返回值。外部outSide调用f1()后,outSide即可读取到函数f2(),即读取到f1()内部n的值。
//闭包实例
function f1(){
var n=1;
function f2(){
//f2函数可以访问到f1的局部变量n
alert(n);
}
//将f2作为返回值
return f2;
}
var outSide=f1();
outSide(); // 1
-
将变量值始终保持在内存中
首先看一下正常情况下的局部变量的生存期
function f1(){
var n = 1; //定义局部变量n
alert(n);
}
f1();// 1
//在调用完f1()后,局部变量n会被删除
如果使用了闭包
var numAdd;
function f1(){
var num = 1; //局部变量,生存期在f1()调用完以后被删除,但使用闭包后就不会被删除了
//匿名函数
numAdd = function(){
num+=1
}
function f2(){
alert(num)
}
return f2;
}
var outSide = f1();//注意这里outSide的值是f2(),为f1() return的值
outSide(); // 弹出1
numAdd();
//闭包使得变量始终保持在内存中
outSide(); //弹出2 //num并没有被删除
numAdd();
outSide(); //弹出3
这是为什么呢?
f2()被赋给了一个全局变量outSide,这导致f2()始终在内存中,而f2()的存在依赖于f1(),因此f1()也始终在内存中,不会在调用结束后,被垃圾回收机制回收。
使用闭包的注意点
- 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
- 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。