
本文翻译自:
https://dev.to/lydiahallie/javascript-visualized-scope-chain-13pd
这次我们讲讲 JS 的作用域链。本文建立在大家已经了解执行上下文的基础上。
请看以下代码:
const name = "Lydia"
const age = 21
const city = "San Francisco"
function getPersonInfo() {
const name = "Sarah"
const age = 22
return `${name} is ${age} and lives in ${city}`
}
console.log(getPersonInfo())
这是在调用getPersonInfo
函数,该函数返回的字符串包含变量name
,age
和city
的值:Sarah is 22 and lives in San Francisco
。但是,getPersonInfo
函数不是不包含变量city
吗?那么又是如何知道city值的呢?
首先,存储空间针对不同的上下文而设置。我们有默认的全局上下文:浏览器中的window
,Node中的global
,以及已调用的getPersonInfo
函数的当前上下文。每个上下文也都有一个作用域链。
对于getPersonInfo
函数,作用域链看起来像这样:

作用域链基本上是一条对象的“引用链”,对象包含对在该执行上下文中可引用的值(和其他作用域)的引用。作用域链是在创建执行上下文时创建的,这意味着它是在运行时创建的!
但是,在本文中,就不讨论活动对象和执行上下文了,我们只关注作用域!在以下示例中,执行上下文中的键/值对表示作用域链对变量的引用。

全局执行上下文的作用域链引用了3个变量:值为Lydia
的name
变量,值为21
的age
变量,以及值为San Francisco
的city
变量。在本地上下文中,引用了2个变量:值是Sarah
的name
变量,值为22
的age
变量。
当我们尝试访问getPersonInfo
函数中的变量时,引擎首先检查本地作用域链。

本地作用域链中有对name
和age
的引用!name
有值Sarah
,age
有值22
。那么现在,当尝试访问city
时会发生什么呢?
为了找到city的值,引擎沿着作用域链往下走。基本上,引擎不会轻易放弃:它会尽全力去查看是否可以在本地范围所引用的外部作用域中(在本例中就是全局对象)找到变量city
的值。

在全局上下文中,我们用值San Francisco
声明了变量city
,因此有了对变量city
的引用。既然我们有了变量的值,那么函数getPersonInfo
就可以返回字符串Sarah is 22 and lives in San Francisco
。
我们可以沿着作用域链往下走,但不能沿着作用域链往上走。看到这里,可能你就觉得困惑了,这里的往上走和往下走是什么意思呢?那我再说明一下:你可以进入外部作用域,但不能进入更内部的作用域。用一种可视化的方式描述的话有点像瀑布:

甚至更进一步:

让我们以这段代码为例。

跟之前的几乎一模一样,但是有一个很大的区别在于:我们现在只在getPersonInfo
函数中声明了city
,而没有在全局作用域中声明。我们没有调用getPersonInfo
函数,因此也没有创建本地上下文。同样的,我们试着在全局作用域内访问name
,age
和city
的值。

抛出了ReferenceError
!因为无法在全局作用域内找到对变量city
的引用,也没有可查找的外部作用域,因此它无法往上进入作用域链。
从这方面看,我们也可以将作用域用作保护变量和重用变量名的方法。
除了全局和局部作用域外,还有一个块作用域。使用let
或const
关键字声明的变量,其作用域范围为最接近的大括号({}
)。
const age = 21
function checkAge() {
if (age < 21) {
const message = "You cannot drink!"
return message
} else {
const message = "You can drink!"
return message
}
}
将作用域可视化:

可以看到有一个全局作用域,一个函数作用域和两个块作用域。由于变量的作用域局限在大括号内,因此我们能够声明变量message
两次。
快速回顾:
作用域链可以视为对可在当前上下文中访问的值的引用链。 作用域还可以重用在作用域链下游定义的变量,因为只能沿着作用域链向下进行,而不能向上。
作用域(链)就是这样!关于这方面其实还有很多值得说一说的内容,学海无涯嘛。感谢阅读。
(文本完,感谢阅读)

每日分享前端插件干货,欢迎关注!
点赞和在看就是最大的支持❤️




