最简单的学习JavaScript闭包

129 阅读2分钟

前言

对于每个正在学习JavaScript的童鞋们,相信你们或多或少的都在百度上搜索过闭包,但百度过后对闭包的理解就更加模糊了。作为学习JavaScript中的一员,我也不例外。接下来我尽量用一种很容易让我们接受的一种方式来讲述闭包。

概念

当你在编写JavaScript代码时,如果当你在一个函数中嵌套了一个或者多个函数,并且将其中的几个函数作为返回值返回到了全局,这样返回的几个函数和最外层的函数就构成了闭包。

    function a (){
        var a = 3
        return function b (){
            console.log("闭包的构成")
        }
    }
    let c = a()
    c()

从作用域链来理解闭包

在函数执行前的非常小的一段时间内,会有一个全局GO对象,和与函数相关的AO对象生成。这些对象会去收集声明的变量和函数。具体的过程如下:

创建AO对象(Activation Object)

  • 创建对象AO
  • 找到函数的形参和变量声明,将变量声明和形参作为AO的属性名,值为undefined
  • 将实参和形参值统一
  • 在函数体里找函数声明,将函数名作为AO对象的属性名,值赋予函数体

创建对象GO(Global Object)

  • 创建对象GO
  • 找到变量声明,将变量声明作为GO的属性名,值为undefined
  • 在全局里面找函数声明,将函数名作为GO对象的属性名,值赋予函数体
    // AO: {
    //     a: undefined 1 3
    //     b: undefined function(){} 2
    //     c: undefined 0 
    //     d: function(){}
    // }



function test(a, b) {
    console.log(a)
    c = 0
    var c
    a = 3
    b = 2
    console.log(b)
    function b() {}
    function d() {}
    console.log(b)

}
test(1)

说明

被执行的返回函数们可以共享外层函数的AO对象里面的一些属性,可以以下一节第二个例子为参考。

闭包的作用

  • 实现公有变量
function test() {
    var count = 0
    return function a (){
        count++
        console.log(count)
    }
}
let fn = test()
fn() //1
fn() //2
fn() //3
  • 做缓存
function fruit () {
    var food = 'apple'
    var obj = {
        eatFood: function () {
            if(food != ''){
                console.log(`I am eating ${food}`)
                food = ''
            }
            else{
                console.log('There is nothing!')
            }
        },
        pushFood: function (myfood) {
            food = myfood
        }
    }
    return obj
}
var person = fruit()
person.eatFood()
person.eatFood()
person.pushFood('banana')
person.eatFood()

闭包对于更高级的开发还有一下特点

  • 可以实现封装,属性的私有化

  • 模块化开发,防止污染全局变量