0%

JS闭包

闭包

  • 如何产生闭包
    当一个嵌套的内部子函数引用了嵌套的外部父函数的变量(函数)时,就产生了闭包
  • 闭包到底是什么
    包含被引用变量(函数)的对象(闭包存在于嵌套的内部函数中)
  • 产生闭包的条件 函数嵌套+内部函数引用了外部函数的数据(变量/函数)+执行内部函数定义(可以不调用内部函数)
    1
    2
    3
    4
    5
    6
    7
    function 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
    12
    function 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
    6
    function showDelay(msg,time){
    setTimeout(function(){
    alert(msg)
    },time)//回调函数是内部函数,showDelay是外部函数
    }
    showDelay("xiaoming",2000)

    闭包的作用

  • 使得内部函数的变量在函数执行完后,仍然存活在内存中(延长了局部变量的生命周期)
  • 使函数外部可以操作(读写)到函数内部的数据(变量/函数)

作用域作用:隔离变量(外部看不到内部变量,但内部可以看到外部(作用域链))

闭包的生命周期

  • 产生:在嵌套的内部函数定义执行完就产生了
  • 死亡:在嵌套的内部函数成为垃圾对象时

数据放到对象中不是私有的,对象的属性是直接可见的,而函数可以产生块级作用域,产生私有变量(对象不行)

闭包应用

  • 定义JS模块
    • 具有特定功能的JS文件
    • 将所有的数据和功能封装在一个函数内部(私有的)
    • 只向外暴露一个包含n个方法的对象或者函数
    • 模块使用者只需要通过模块暴露的对象调用方法实现相应功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// <module1.js>
function module1(){
var data=1
function increase(){
data++
console.lag(data)
}
function decrease(){
data--
console.log(data)
}
return{
increase:increase,
decrease:decrease
}
}
//test1.js
var module = module1()
module.increase()
module.decrease()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// <module2.js>
(function (window){//匿名函数
var data=1
function increase(){
data++
console.lag(data)
}
function decrease(){
data--
console.log(data)
}
window.module2 = {
increase:increase,
decrease:decrease
}//不传的话由于作用域链可以找到window
})(window)//window可传可不传(但是为了代码压缩的方便加上(若不加代码压缩将window替换成字母则w.module不会加到全局window上))
//test2.js
module2.increase()
module2.decrease()

第一种方式需要先执行函数才能调用,第二种方式直接引入js文件后就全局可见