一、什么是闭包
闭包(closure)就是能够读取其他函数内部变量的函数。在js中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成 “定义在一个函数内部的函数”。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
简单来说就是,当一个嵌套的函数内部调用了嵌套外部函数中的变量时,就会产生闭包,并且只执行外部函数(执行内部函数定义)就会产生闭包,甚至不用调用内部函数。
(闭包的最典型的应用是实现回调函数(callback) )。
二、闭包的应用
闭包的应用有将函数作为另一个函数的返回值;将函数作为实参传递给另一个函数调用
闭包的最典型的应用是实现回调函数(callback)
例子如下:
// 1. 将函数作为另一个函数的返回值
function fn1() {
var a = 2
function fn2() {
a++
console.log(a)
}
return fn2//将内部函数作为返回值返回(函数也是数据,是数据就能返回)
};
var f = fn1()
f() // 3,执行这个f()实际上是执行了f1中的内置函数
f() // 4,闭包产生几次,就看外部函数调用几次,这里的两个f()实际上都是调用内部函数fn2()
// 2. 将函数作为实参传递给另一个函数调用
function showMsgDelay(msg, time) {
setTimeout(function () {
console.log(msg) //闭包里面只有msg,time不在内部函数中
alert(msg)
}, time)
}
showMsgDelay('hello', 1000)
三、闭包的作用和缺点
作用
1. 使函数内部的变量在函数执行完后,仍然存在于内存中,延长局部变量的生命周期(用的太多就变成了缺点,占内存)
2. 让函数外部可以操作内部的数据(变量、函数)
3. 逻辑连续,当闭包作为另一个函数调用的参数时,避免你脱离当前逻辑而单独编写额外逻辑
4. 方便调用上下文的局部变量
5.加强封装性,可以达到对变量的保护作用,保护函数内的变量安全
缺点
函数执行完以后,内部局部变量没有释放,占用内存,容易造成内存泄漏,因此能不用闭包就不用,或者及时释放(很重要)
回收例子如下:
function fn1() {
var arr = new array[100000]
function fn2() {
console.log(arr.length)
}
return fn2;
}
var f = fn1();
f();
f = null // 让内部函数成为垃圾对象-->回收闭包,清除引用
问题:
函数执行完后,函数内部声明的局部变量是否存在?
答:一般不存在,存在于闭包中的变量才“可能”存在(即存在引用关系,引用了外部变量)
函数外部可以直接访问到内部的局部变量吗?
答:不能,但是可以通过闭包来操作
四、闭包的生命周期
产生:在嵌套内部函数定义执行完时就产生(不是在调用)
死亡:嵌套的内部函数成为垃圾对象时
function fn1() {
//此处闭包已经产生(函数提升,内部函数对象已经创建)
var a = 3
function fn2() { //若写成var fn2 = function (){...},则是在此处(函数定义完)产生
a++
console.log(a)
}
return fn2
}
var f = fn1()
f()//3
f()//4 //在这里闭包还未死亡
f = null //此时闭包对象死亡(包含闭包的对象成为垃圾对象),引用fn1的变量不再引用它