JS闭包理解
首先,JavaScript的变量只有两种:即为全局变量和局部变量;
因为JavaScript语言的链式作用域结构,子对象可以一级一级的向上寻找父对象的变量,所以,父对象的所有变量对子对象都是可见的,但是因为是单向作用域链,所以反之不成立
所以到现在,函数内部可以直接读取全局变量,如:
var a = 1
function demo1() {
alert(a)
}
demo1() // 弹出数值为1的提示框
但是,如果想要在函数外部读取函数内的局部变量却无法做到,如
function demo1() {
var a = 1
}
alert(a) // 错误,提示a没有定义,
注意,如果在函数中不使用var来定义变量,如直接a=1,则a会成为全局变量,如
function demo1() {
a = 1
}
demo1() //这里要先执行一下函数,否则a不会被声明
alert(a) // 弹出数值为1的提示框
那么,想要实现在函数外部读取函数内的局部变量的操作,就要用到闭包,如
function demo1() {
var a = 1 // 局部变量
function demo2() { //如何实现闭包:即在函数的内部再定义一个函数
a += 1 //因为作用域链,所以此处可以访问到a
console.log('此a为:' + a)
}
return demo2 //这里返回的函数不用加括号,即返回函数名不加括号,调用函数的时候才加括号
}
console.log(typeof(demo1())) //输出function,如果上面return 的是demo2(),那么返回undefined,并且报错
var result = demo1() //先执行函数,给变量赋值
console.log(typeof(result)) //输出function,如果上面return 的是demo2(),那么返回undefined,并且报错
result() // 执行函数,实现对局部变量a的访问
result()
result()
result()
result()
闭包的用途:
1.读取函数内部的变量
2.让函数内部的变量的值始终保存在内存中,如
function demo1() {
var n = 1
add = function() { // 这里是一个全局变量
n += 1
}
// return n
function demo2() {
alert(n)
}
return demo2
}
var result = demo1()
result() // 显示1
add()
result() //显示2
// console.log(demo1())
// add()
// console.log(demo1())
在这段代码中,result即为闭包demo2函数,第一次的值为1,第二次的值为2,这证明了函数demo1中的局部变量n一直保存在内存中,并没有在demo1被调用后被回收
这里demo1是demo2的父函数,而demo2被赋给了一个全局变量result,这导致demo2始终在内存中,而demo2的存在依赖于demo1,所以demo1也是种存在于内存中,不会在调用结束后被回收机制回收
这里的add函数其实是一个全局变量,如果把闭包函数demo2注释掉,运行下面注释的语句,就会发现两次输出的值都是1,这是因为局部变量在第一次被调用结束后被回收了,即使执行了全局函数add,也不会对局部变量n产生影响,这恰恰验证了闭包使局部变量的值始终存在于内存中,不会因调用结束而被回收
使用闭包的注意点:
1.由于闭包会使得函数中的变量都被保存在内存中,会占用内存,所以不能滥用闭包,否则会造成网页的性能问题,可能导致内存泄漏。解决方法是在退出函数之前,将不使用的局部变量全部删除(delete或者设置该变量为null)
2.闭包会在函数外部,改变函数内部变量的值,所以一定要小心使用,不能随便改变父函数内部变量的值
可以执行一下下面两个demo,挺有意思的
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); // 这里把立即执行的括号去掉输出一下就很清楚了,我的理解是这个demo里没有闭包,被返回的函数没有属于的对象,所以this指向全局。
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); //而这里因为有一个that,所以它需要依赖getNameFunc这个函数,就形成了一个闭包,局部变量会一直在内存中,that点的就是局部变量的值