(译)看得见的 JavaScript: 作用域(链)Scope (Chain)

简介: (译)看得见的 JavaScript: 作用域(链)Scope (Chain)
var code = "8aecffca-8909-4927-a3e0-49a8d64e4bd6"

让我们看一下以下这段代码:

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,它将返回一个由 nameagecity 变量组成的字符串:Sarah is 22 and lives in San Francisco。但是,getPersonInfo 函数里并未包含一个叫做 city 的变量,它是怎么知道 city 的值的呢?

首先,不同的上下文都会被分配不同的内存空间。我们拥有默认的全局上下文(浏览器里是 window,在 Node 中是 global),以及一个局部上下文,它是在 getPersonInfo 函数被调用时出现的。每一个上下文都会有一个作用域链

对于 getPersonInfo 函数,作用域链看起来有点像下面这样(不必担心,暂时可以不用理解它):


10.jpg


作用域链基本上就是一个对象的“引用链条”,它将包含当前执行上下文中所有值的引用。当执行上下文被创建的时候,作用域链就出现了,也就是说,它是在运行时被创建的。

然而,在这篇文章中,我并不打算讨论 activation object (活跃对象或激活对象)或是执行上下文,让我们聚焦作用域!在接下来的例子中,执行上下文中的键值对代表作用域链中变量的引用。


11.jpg


全局执行上下文中的作用域链有一条对 3 个变量的引用:带有值 Lydia 的变量 name,带有值 21 的变量 age,以及带有值 San Francisco 的变量 city。在局部上下文中,我们有一条对 2 个变量的引用:带有值 Sarah 的变量 name,以及带有值 22 的变量 age

当我们试着获取 getPersonInfo 函数中的变量时,引擎首先会检查局部作用域。


12.jpg


局部作用域链中含有一条对 nameage 的引用!name 中的值是 Sarahage 中的值是 22。但是现在,当它试着去获取 city 时会发生什么?

为了找到 city 的值,引擎将会顺着作用域链向下找。这基本上意味着引擎不会简单地放弃查找:它会为你努力工作,看看是否可以在局部作用域外部找到变量 city,这本例中,这个外部作用域就是全局对象(global object)


13.jpg


在全局上下文中,我们定义了变量 city,它的值是 San Franciso,因此就有了对变量 city 的引用。既然这个变量有对应的值,那么函数 getPersonInfo 就能返回出字符串 Sarah is 22 and lives in San Francisco

我们沿着作用域链向下找,但是不会反过来向上找。(好吧,这也许会令人很疑惑,因为有些人的说法正好相反,下说成上,因此我要提一句的是:你可以沿着作用域链向外找,而不是向内找……)我喜欢将它想象成瀑布:


14.jpg


甚至更深层次的:


15.jpg


让我们以这段代码为例。


16.jpg


跟之前的例子相比,几乎是一样的,一个比较大的差异是:我们现在只在 getPersonInfo 函数中声明了变量 city,而不是在全局作用域。我们没有去调用 getPersonInfo 函数,也就没有局部上下文被创建。此时,我们试着在全局上下文中获取变量 nameage 以及 city 的值。


17.jpg


它将会抛出错误:ReferenceError!在全局作用域中,它找不到 city 对应的引用值,也没有其他外部的作用域了,它不能再继续往上找了。

这样一来,你就能利用作用域作为一种保护变量的途径,而且可以出现同名变量。

除了全局和局部作用域,还有一个块级作用域。用 letconst 关键字声明的变量被限制在最近的大括号({})中。

const age = 21
function checkAge() {
  if (age < 21) {
    const message = "You cannot drink!"
    return message
  } else {
    const message = "You can drink!"
    return message
  }
} 

你可以将作用域想象成这样:


18.jpg


我们有一个全局作用域,一个函数作用域以及两个块级作用域。我们可以声明变量 message 两遍,因为变量的范围在大括号中,彼此独立、互不影响。

快速回顾一下:

  • 你可以把作用域链当作一条可以访问到当前上下文中值的引用链条。
  • 作用域能够让变量名称重复成为可能。



目录
相关文章
|
4月前
|
JavaScript 前端开发
js的作用域作用域链
【10月更文挑战第29天】理解JavaScript的作用域和作用域链对于正确理解变量的访问和生命周期、避免变量命名冲突以及编写高质量的JavaScript代码都具有重要意义。在实际开发中,需要合理地利用作用域和作用域链来组织代码结构,提高代码的可读性和可维护性。
|
4月前
|
自然语言处理 JavaScript 前端开发
[JS]作用域的“生产者”——词法作用域
本文介绍了JavaScript中的作用域模型与作用域,包括词法作用域和动态作用域的区别,以及全局作用域、函数作用域和块级作用域的特点。通过具体示例详细解析了变量提升、块级作用域中的暂时性死区等问题,并探讨了如何在循环中使用`var`和`let`的不同效果。最后,介绍了两种可以“欺骗”词法作用域的方法:`eval(str)`和`with(obj)`。文章结合了多位博主的总结,帮助读者更快速、便捷地掌握这些知识点。
52 2
[JS]作用域的“生产者”——词法作用域
|
4月前
|
前端开发 JavaScript 数据处理
CSS 变量的作用域和 JavaScript 变量的作用域有什么不同?
【10月更文挑战第28天】CSS变量和JavaScript变量虽然都有各自的作用域概念,但由于它们所属的语言和应用场景不同,其作用域的定义、范围、覆盖规则以及与其他语言特性的交互方式等方面都存在明显的差异。理解这些差异有助于更好地在Web开发中分别运用它们来实现预期的页面效果和功能逻辑。
|
4月前
|
JavaScript 前端开发
javascript的作用域
【10月更文挑战第19天javascript的作用域
|
4月前
|
JavaScript 前端开发
如何在 JavaScript 中实现块级作用域?
【10月更文挑战第29天】通过使用 `let`、`const` 关键字、立即执行函数表达式以及模块模式等方法,可以在JavaScript中有效地实现块级作用域,更好地控制变量的生命周期和访问权限,提高代码的可维护性和可读性。
|
5月前
|
JavaScript 前端开发
JavaScript 作用域
JavaScript 作用域是指程序中可访问的变量、对象和函数的集合。它分为函数作用域和局部作用域。函数作用域内的变量仅在函数内部可见,而全局作用域的变量在整个网页中均可访问。局部变量在函数执行完毕后会被销毁,而全局变量则在整个脚本生命周期中都存在。未使用 `var` 关键字声明的变量默认为全局变量。
|
5月前
|
JavaScript 前端开发
js作用域
js作用域
39 1
|
6月前
|
JavaScript 前端开发
js 变量作用域与解构赋值| 22
js 变量作用域与解构赋值| 22
|
6月前
|
缓存 JavaScript 前端开发
了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化
该文章详细讲解了JavaScript中的作用域、闭包概念及其应用场景,并简要分析了函数柯里化的使用。
了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化
|
6月前
|
JavaScript 前端开发
JavaScript 作用域
JavaScript 作用域
37 9

热门文章

最新文章