Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript -- 闭包 #15

Open
mt51 opened this issue Oct 26, 2018 · 0 comments
Open

JavaScript -- 闭包 #15

mt51 opened this issue Oct 26, 2018 · 0 comments

Comments

@mt51
Copy link
Owner

mt51 commented Oct 26, 2018

闭包

一直以来都对闭包不太理解,感觉是个很神秘的东西,在深入的了解了执行上下文和作用域之后,终于有些明白了。

这篇文章需要前面几篇文章提到的知识点:

闭包是什么

在《高程》中时这样解释闭包的

闭包是指有权访问另外一个函数作用域中的变量的函数。

通常创建闭包最简单的方式是在一个函数中返回另一个函数。

// 例子
function foo () {
    var x = 123
    return function bar () {
        console.log(x)
    }
}
var baz = foo()

baz()  //  123

内部的函数bar就是个闭包,因为能够访问到外层foo函数的作用域中的变量。

我们将foo返回的函数赋值给baz,调用baz能够输出x的值。

在内部函数bar创建的时候会将foo函数的活动对象AO(foo)保存在bar内部的[[Scope]]属性中。当调用bar函数时会为其构建作用域链,将bar的活动对象AO(bar)bar.[[Scope]] 推入作用域链。使用伪代码来模拟一下:

// 伪代码
Scope(bar) = [ AO(bar), bar.[[Scope]] ] = [ AO(bar), AO(foo) ] = [
    {},
    {
        x: 123,
        bar: <reference to FunctionDeclaration 'bar'>
    }
]

因此当bar函数执行的时候,在自身的执行上下文中找不到标识符x,就会沿着作用域链向上查找,最终找到表示符x并返回。

//  另外一个例子
var data = []
function foo () {
    for (var i = 0; i < 10; i++) {
        data[i] = function () {
            console.log(i)
        }
    }
}
foo()
data[0]()  // 10
data[1]()  // 10

我们期望的是data的每一项都返回自己的索引值。但实际上每一个返回的都是10

分析一下,data的每一项中的函数上下文中都不包含标识符i,会沿作用域向上查找,因此,访问到的都是函数foo中的标识符i,当调用data[0]的时候函数foo已经执行结束,此时函数foo中的i的值为10,因此data的每一项都会返回10

把这个例子改造下,让它符合期望

var data = []
function foo () {
    for (var i = 0; i < 10; i++) {
        data[i] = function (num) {
            return function (){
                console.log(num)
            }
        }(i)
    }
}
foo()
data[0]()  // 0
data[1]()  // 1
内存泄露

正常情况下,当一个函数执行完成之后,使用的内存会被释放掉。但是由于闭包仍在引用着上一级执行上下文的活动对象,因此不会被销毁掉一直留在内存中。可以通过将引用切断来释放内存。

参考

JavaScript高级程序设计

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant