(译)看得见的 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 两遍,因为变量的范围在大括号中,彼此独立、互不影响。

快速回顾一下:

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



目录
相关文章
|
24天前
|
JavaScript
JS作用域(全局作用域+局部作用域)
JS作用域(全局作用域+局部作用域)
9 0
|
26天前
|
JavaScript 前端开发 开发者
深入理解JavaScript作用域与作用域链
深入理解JavaScript作用域与作用域链
29 0
|
29天前
|
存储 缓存 前端开发
揭开 JavaScript 作用域的神秘面纱(下)
揭开 JavaScript 作用域的神秘面纱(下)
揭开 JavaScript 作用域的神秘面纱(下)
|
29天前
|
JavaScript 前端开发
揭开 JavaScript 作用域的神秘面纱(上)
揭开 JavaScript 作用域的神秘面纱(上)
揭开 JavaScript 作用域的神秘面纱(上)
|
1月前
|
存储 JavaScript 前端开发
【JavaScript】<面向对象Object>函数方法&对象创建&原型对象&作用域解析
【1月更文挑战第17天】【JavaScript】<面向对象Object>函数方法&对象创建&原型对象&作用域解析
|
1月前
|
自然语言处理 JavaScript 前端开发
JavaScript:作用域&变量回收
JavaScript:作用域&变量回收
27 1
|
1月前
|
JavaScript 前端开发 Shell
深入学习JavaScript系列——作用域和作用域链
深入学习JavaScript系列——作用域和作用域链
|
1月前
|
存储 自然语言处理 前端开发
【面试题】三道面试题让你掌握JavaScript中的执行上下文与作用域以及闭包
【面试题】三道面试题让你掌握JavaScript中的执行上下文与作用域以及闭包
|
2月前
|
存储 Web App开发 自然语言处理
聊一聊 JavaScript 中的作用域和闭包
起因是最近了解JS执行上下文的时候,发现很多书籍和资料,包括《JavaScript高级程序设计》、《JavaScript权威指南》和网上的一些博客专栏,都是从 ES3 角度来谈执行上下文,用ES6规范解读的比较少,所以想从ES6的角度看一下执行上下文。 下面我尝试用[ECMAScript 6规范](https://262.ecma-international.org/6.0)文档,来聊聊执行上下文
113 0
聊一聊 JavaScript 中的作用域和闭包
|
2月前
|
自然语言处理 前端开发 JavaScript
【前端|Javascript第3篇】探秘JavaScript的作用域与作用域链:小白也能轻松搞懂!
【前端|Javascript第3篇】探秘JavaScript的作用域与作用域链:小白也能轻松搞懂!

相关产品

  • 云迁移中心