JavaScript高级深入浅出:作用域链的查找规则

264 阅读2分钟

介绍

本文是 JavaScript 高级深入浅出系列的第三篇,详细介绍了作用域链的查找规则

正文

在第二篇中,我们在解析执行函数的过程中,提到了console.log将找到父级作用域中的 console 类,最终找到 log 方法,接下来我们将详细了解这一过程。

var name = 'alex'

foo()
function foo() {
    console.log(name)  // alex
}

foo函数中并未定义 name,那么就说明该函数所属的AO中并没有 name。但是由于全局对象 GO 中有 name,所以最终打印出 alex。实际上,要找一个变量是根据作用域链查找的。

在函数所属的 FEC 中,除了有 AO,其实还有 scope chain,也就是作用域链

scope chain由两部分组成:

  • 当前作用域的 AO
  • 父级作用域 parent scope

在上文的代码片段中,foo的 parent scope 就是全局作用域,因此在寻找name变量时,首先会在自己的 AO 中寻找,找不到就会在父级作用域中的 VO 也就是 GO 中寻找,假设父级作用域还没有,就会去父级作用域的父级作用域中找,最终找到 name 并打印

举例说明

var name = 'alex'

foo()
function foo() {
    var n1 = 123
    function bar() {
        var n2 = 456
        console.log(name)
    }
    bar()
}

作用域链

在执行阶段:

  • 当执行bar函数中的console.log(name)时,开始在所属 AO 中找,并没有 name
  • 接下来会根据所属 FEC 中的 parent scope 去找foo函数中是否有 name
  • 在 foo 的 AO 中还没有,将根据 foo 所属的 FEC 中 parent scope 去找 name
  • 最终在全局对象 GO 中找到 name,并打印
  • bar函数执行完毕,所属 FEC 弹出 ECStack
  • foo函数执行完毕,所属 FEC 弹出 ECStack

总结

本文中,你学到了一个知识:

作用域链的查找规则

在函数的 FEC 内部,会存在一个 scope chain,由本作用域的 AO + 父级作用域组成。

在查找某个变量时,在所属 AO 中找不到就会沿着 scope chain 一层一层往上查找,直到找到或 GO 中找不到报错为止。