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

JS深入浅出 - 闭包 #7

Open
jtwang7 opened this issue May 10, 2021 · 0 comments
Open

JS深入浅出 - 闭包 #7

jtwang7 opened this issue May 10, 2021 · 0 comments

Comments

@jtwang7
Copy link
Owner

jtwang7 commented May 10, 2021

JS深入浅出 - 闭包

参考文章:
JavaScript深入之闭包

概念

以下是不同网站、书籍对闭包的定义。

  • 一个内部函数保持着其对外部函数词法作用域的访问权限。
  • 一个函数对其周围状态(词法环境)的引用, 与该函数捆绑在一起的组合称为闭包。
  • 保护一个可重用的局部变量的词法结构。
  • 当函数可以记住并访问所在的词法作用域时, 就产生了闭包, 即使函数是在当前词法作用域之外执行。(《你不知道的JavaScript》)
  • 闭包是指那些能够访问自由变量的函数。(MDN)

自由变量:在函数中使用的,但既不是函数参数也不是函数的局部变量的变量。

简单理解:闭包就是一个持有对其外部函数词法作用域访问权限的函数。

闭包 = 函数 + 持有外部变量的访问权限

闭包分析

当你仔细理解了 JS 的执行上下文后,你就会发现:闭包其实是 JS 运行执行上下文时的产物!
看例子!

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}

var foo = checkscope();
foo();

JS 引擎在执行上述代码时的简要过程:

  1. 进入全局代码,创建全局执行上下文,全局执行上下文入栈。
  2. 全局执行上下文创建(变量对象,作用域链,this 对象),执行全局执行上下文。
  3. 执行到 checkscope 函数时,创建 checkscope 函数执行上下文,checkscope 执行上下文压入栈顶。
  4. checkscope 执行上下文初始化,创建变量对象、作用域链、this等。
  5. checkscope 函数执行完毕,checkscope 执行上下文从栈顶弹出。
  6. 执行 foo 函数,创建 foo 函数执行上下文,foo 执行上下文入栈。
  7. foo 执行上下文初始化,创建变量对象、作用域链、this等。
  8. foo 函数执行完毕,foo 函数上下文从执行上下文栈顶弹出。

Question:
当 foo 函数执行的时候,checkscope 函数上下文已经被销毁(即从执行上下文栈中被弹出),怎么还会读取到 checkscope 作用域下的 scope 值呢?

Answer:
依赖于作用域链!

我们知道 foo 执行上下文维护了一个作用域链:

fContext = {
    Scope: [AO, checkscopeContext.AO, globalContext.VO],
}

就是因为这个作用域链,foo 函数依然可以读取到 checkscopeContext.AO 的值,说明当 foo 函数引用了 checkscopeContext.AO 中的值的时候,即使 checkscopeContext 被销毁了,但是 JavaScript 依然会让 checkscopeContext.AO 活在内存中,foo 函数依然可以通过 foo 函数的作用域链找到它,正是因为 JavaScript 做到了这一点,从而实现了闭包这个概念。

闭包应用

闭包常用于保存或保护变量的访问权限。

  • 私有变量
  • 回调与计时器
  • 绑定函数上下文
  • 偏应用函数
  • 函数重载: 缓存记忆 / 函数包装
  • 即时函数: 独立作用域 / 简介代码 / 循环 / 类库包装 / 通过参数限制作用域内名称

缺点: 闭包信息始终会保存在内存里。

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

No branches or pull requests

1 participant