2049观察者

作用域链scope chain,闭包closure

Red Yin
Red Yin

JS 引擎在执行代码时候,会专门有一个执行环境栈。最初 push 进去的为全局执行上下文,代码执行遇到局部作用域({}语句、函数等)时就会生成其相应的执行上下文并 push 进去,执行完毕就会 pop 出栈。一直到最后,全局执行上下文被 pop 出栈时,那么当前执行环境栈为空,即此 JS 脚本运行完毕!

执行函数时会 push 进去此函数的执行上下文。和全局执行上下文唯一不同的是,函数执行上下文不需要初始化全局对象,而是会创建一个 arguments 对象(一个储存了函数所有的参数变量数组)。

调用一个变量时,如果在当前执行环境中未找到相应的值,则会沿着执行环境栈里的顺序,依次向上寻找变量,一直到栈顶即全局执行环境为止。如在环境找到变量,就立即返回相应值,不再往上寻找。这一寻找过程的链称为作用域链(Scope Chain)

按照执行环境栈的道理,通常情况下,外部环境无法访问一个局部作用域环境的变量。例如:

{
 let a = {};
}
console.log(a); //ReferenceError

而有一种特殊情况,一个函数返回的值是一个函数。例如:

function outer(){
    let a = {};

    function inner(){
      console.log(a);
    }

    return inner;
}

let b = outer();

在这里执行 outer 函数,并把返回值赋值给 b.那么 b 变量就是 inner 函数,而且会保留对 outer 函数内部环境的引用。以此现在全局执行环境可以通过 b 变量访问 outer 函数内部的变量。

闭包(closure)是指内部函数总是可以访问其所在的外部函数中声明的变量和参数,即使外部函数已经被返回了,就是外部函数执行调用完了之后。