closure闭包作用域链

闭包是什么

闭包就是匿名函数返回的函数

前置知识

  • 每个函数都有[[Scopes]]属性。里面存着此函数的:
    1. 作用域
    2. 每个作用域内的必要的值的引用。

闭包函数创建流程

两个关键函数:创建函数返回函数

  1. 创建函数(iife 立即执行函数、匿名函数)执行。
  2. 创建函数扫描 AST 树,分析返回函数的外部作用域的值的引用。
  3. 返回函数外部作用域中,被返回函数引用到的值入栈在返回函数[[Scopes]]属性里,如[{ dep1: "123" }, window]
  4. 创建函数执行完毕,创建函数作用域销毁。

等到执行返回函数的时候,会利用[[Scopes]]属性这个「快照」,恢复返回函数所需要用到的作用域链。

其他

  • 创建函数在分析返回函数的依赖的时候,发现如果返回函数内有eval代码,将会把之前整个作用域的参数都入栈到[[Scopes]]属性。
    • 并且返回函数中的每个函数的[[Scopes]]属性都会有所有的作用域链参数。这就是为什么不提倡用eval的一个重要原因。
  • 如果闭包函数一直在调用,就会导致内存减少,即内存泄漏。
  • 释放内存:将闭包函数的变量赋值为null

调试demo

function A() {
  const uselessA = "uselessA";
  const insA = "insA";
  function B() {
    const uselessB = "uselessB";
    const insB = "insB";
    console.log(insA);
    // eval('console.log(0);')
    function C() {
      console.log(uselessA);
      console.log(insB);
      // eval('console.log(0);')
      return 0;
    }
    return C;
  }
  return B();
}
const fn = A();
fn();