主要参考:阮一峰博客
js变量作用域
在理解闭包之前,需要先理解js中变量的作用域。
js中的变量分为全局变量和局部变量。
var m = 'hello'
function a () {
var mm = 'world'
console.log(m) // hello
}
console.log(m) // hello
console.log(mm) // undefined 报错
m为全局变量,mm 为函数内部的局部变量,在函数内部可以访问全局变量,但是在函数外部不可以访问函数内部的局部变量。
函数内部的变量在声明时使用 var mm = ‘world’ 则声明的变量为局部变量 ,若省略var 使用 mm = ‘world’,则声明的变量为全局变量。
若想要在函数外部访问函数内部的变量呢? 这时候就出现了闭包。
什么是闭包
闭包简单概括一句话就是 能够访问其他函数内部变量的函数。
下面用一张图来说明
如上图所示,有function 1、 function 2、function3 三个方法,
function2 → funciton1中变量a √
function3 → function1中变量a ×
在function2中可以访问function1中的变量a,这是由于原型链的原因,可以访问。
在function3中不能访问function1中的变量a,函数外部不能访问函数内部的变量。
如果想要访问函数内部的变量呢? 我们该怎么做,通过上图我们已知,function1内部的函数function2是可以访问到函数内部的变量的,那么我把function2 retrun导出,再在外部通过变量接收,不就可以访问function1内部的变量了吗,这就是闭包的由来。
简单代码
function function1 () {
var a = 1
function function2 () {
console.log('a:'+a)
}
return function2
}
var result = function1()
result()
运行结果如下:
如上例子中function2 即为闭包。闭包是函数内部变量和函数外部的连接桥梁,使得外部函数可以访问函数内部的变量。
闭包的使用
function f1() {
var n = 999;
nAdd = function() {
n += 1
}
function f2() {
console.log(n);
}
return f2;
}
var result = f1();
result(); // 999
nAdd();
result(); // 1000
如上代码,result为闭包,var result = f1() ,将f1赋值给result,而f1中返回值为f2,则result为闭包。
第一次调用result() 输出999
调用nAdd()函数后,再调用result() 输出1000
可见在函数执行完后,函数中的变量并没有被垃圾回收机制给回收,因为将f1赋值给了result全局变量,变量被保存到了内存中,全局变量不会被回收。
nAdd = function() {n+=1} 这里的nAdd前没有var,所以为全局变量,可以在函数外被访问,nAdd相当于setter,对f1中的变量进行操作。
使用闭包的注意点
1.闭包使用的过程中,会将函数内部的变量变成全局变量存储到内存中,如果大量使用闭包,会导致内存泄漏,因此闭包使用完之后要及时关闭。
2.闭包在使用的过程中,可能会改变原有父函数中的变量值,因此要注意不要随意修改父函数中的变量值。
思考
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()());
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()());