作用域+闭包

一、作用域

[[scope]]的定义:

每一个javascript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供js引擎存取。[[scope]]就是其中之一,[[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合(即:作用域链)。

一切对象都有属性,函数也是对象,函数有属性,如和访问的name属性,不可访问的[[scope]]属性

运行期上下文的定义:

当函数执行时,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时候的环境。函数每次执行时对应的执行上下文都是独一无二的。所以多次调用一个函数会导致创建多个执行上下文。当函数执行完毕,它所产生的执行上下文被销毁。

function test(){}
test() //-> AO{},即时的存储空间,执行完被销毁
test() //-> AO{}
复制代码

作用域链的定义:

[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式连接,我们把这种链式链接叫作用域链

function a() {
    function b() {
        var b = 234
    }
    var a = 123
    b()
}
var global = 100
a()
复制代码

<1> a定义时产生的 — a刚出生时存的是它所在环境的执行期上下文
image.png
<2> a执行时产生一个AO,放在作用域链的顶端
image.png
<3> a执行完销毁自己的AO,回到被定义状态
image.png

b执行时同理 !!
b中的AO(a的) 和 a中的AO(a的) 是一样的,拿的是一个引用。

function a() {
    function b() {
        function c(){}
        c()
    }
    b()
}
a()
复制代码

a定义 a.[[scope]] -> 0:GO
a执行 a.[[scope]] -> 0:AO(a)、1:GO
b定义 b.[[scope]] -> 0:AO(a)、1:GO
b执行 b.[[scope]] -> 0:AO(b)、1:AO(a)、2:GO
c定义 c.[[scope]] -> 0:AO(b)、1:AO(a)、2:GO
c执行 c.[[scope]] -> 0:AO(c)、1:AO(b)、2:AO(a)、3:GO
里面可以访问外面的,外面的看不见里面的

查找变量:从作用域链的顶端依次向下查找。在哪个函数里面查找变量,就上哪个函数的作用域链的顶端依次向下查找。

一、闭包

定义:

当内部函数被保存到外部时,将会生成闭包。

缺点:

闭包会导致原有作用域链不释放,造成内存泄漏(内存占用多了,所剩的少了,理解为泄漏)。

作用:

1.实现公有变量 eg:函数累加器(例3)
2.可以做缓存(存储结构) eg:(例5)
3.可以实现封装,属性私有化 eg:Person()
4.模块化开发,防止污染全局变量

例子:

function a() {
    function b() {
        var bbb = 234
        console.log(aaa)  //123
    }
    var aaa = 123
    return b
}
var global = 100
var demo = a() //此处a执行完了,要销毁,但是return b,所以AO(a)还跟b连着,未被销毁。
demo()
复制代码

但凡内部的函数被保存到了外部,一定是闭包。因为内部函数保留了外部函数的劳动成果。
2.

function a() {
    var num = 100
    function b() {
        num++
        console.log(num)
    }
    return b
}
var demo = a()//a执行完销毁
demo() //101
demo() //102
复制代码

a销毁时b还未执行,
第一次执行,建立新的AO(b),b拿AO(a)的num,并把AO(a).num-> 101,执行后AO(b)销毁
第二次执行,建立新的AO(b),b拿AO(a)的num,并把AO(a).num-> 101,执行后AO(b)销毁
3.

function add() {
    var count = 0
    function demo() {
        count++
        console.log(count)
    }
    return demo
}
var counter = add()
counter() //1
counter() //2
counter() //3
复制代码
function test() {
    var num = 100
    function a() {
        num++
        console.log(num)
    }
    function b() {
        num--
        console.log(num)
    }
    return [a, b]
}
var myArr = test()
myArr[0]() //101
myArr[1]() //100
复制代码
function eater() {
    var food = ""
    var obj = {
        eat: function () {
            console.log(`eating ` + food)
            food = ""
        },
        push: function (myFood) {
            food = myFood
        }
    }
    return obj
}
var eater1 = eater()
eater1.push("banana")
eater1.eat() //eating banana
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享