闭包
- 如何产生闭包
当一个嵌套的内部子函数引用了嵌套的外部父函数的变量(函数)时,就产生了闭包 - 闭包到底是什么
包含被引用变量(函数)的对象(闭包存在于嵌套的内部函数中) - 产生闭包的条件 函数嵌套+内部函数引用了外部函数的数据(变量/函数)+执行内部函数定义(可以不调用内部函数)
1
2
3
4
5
6
7function fn1(){
var a=2//调用fn1执行到此处时已经产生了闭包(函数提升) 对应此处的执行上下文如下图
function fn2(){
console.log(a)
}//如果采用var fn2 = function()的方式定义函数,则只有在执行到这里时才会产生闭包,var a=2那里函数对象还没创建呢,是undefined,也就不存在闭包了
}
fn1()常见的闭包
- 将函数作为另一个函数的返回值
1
2
3
4
5
6
7
8
9
10
11
12function fn1(){
var a=2
function fn2(){
a++
console.log(a)
}
return fn2
}
var f=fn1()//正常情况下a作为函数局部变量fn1调用结束就死亡,但是由于闭包没有死
f()//3
f()//4 只产生了一个内部函数对象(执行外部函数的时候才会产生内部函数对象,跟内部函数执行几次无关),因此只有一个闭包
f=null//闭包死亡(包含闭包的函数对象成为垃圾对象) - 将函数作为实参传递给另一个函数调用
1
2
3
4
5
6function showDelay(msg,time){
setTimeout(function(){
alert(msg)
},time)//回调函数是内部函数,showDelay是外部函数
}
showDelay("xiaoming",2000)闭包的作用
- 使得内部函数的变量在函数执行完后,仍然存活在内存中(延长了局部变量的生命周期)
- 使函数外部可以操作(读写)到函数内部的数据(变量/函数)
作用域作用:隔离变量(外部看不到内部变量,但内部可以看到外部(作用域链))
闭包的生命周期
- 产生:在嵌套的内部函数定义执行完就产生了
- 死亡:在嵌套的内部函数成为垃圾对象时
数据放到对象中不是私有的,对象的属性是直接可见的,而函数可以产生块级作用域,产生私有变量(对象不行)
闭包应用
- 定义JS模块
- 具有特定功能的JS文件
- 将所有的数据和功能封装在一个函数内部(私有的)
- 只向外暴露一个包含n个方法的对象或者函数
- 模块使用者只需要通过模块暴露的对象调用方法实现相应功能
1 | // <module1.js> |
1 | // <module2.js> |
第一种方式需要先执行函数才能调用,第二种方式直接引入js文件后就全局可见