[译]JavaScript️可视化:作用域链

1,076 阅读4分钟

本系列

正文

现在开始讲作用域链🕺🏼在这篇文章中,我假设您了解执行上下文:尽管如此,我也将很快就此发表一篇文章😃

让我们看下面的代码:

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个变量:name的值是Lydia,age的值是21,city的值是San Francisco。在本地上下文中,我们引用了2个变量:name的值是Sarah和age的值是22。

当我们尝试访问getPersonInfo函数中的变量时,引擎首先检查本地作用域链。

本地作用域链引用了name和age!name的值为Sarah,age的值为22。但是现在,当它尝试访问city时会发生什么?

为了找到city的值,引擎“沿作用域链往下”。这意味着引擎不会轻易放弃:它会努力为您查看是否可以city在本地作用域引用的外部作用域(在本例中为全局对象)中找到变量的值。

在全局上下文中,我们声明了变量city,它的值为San Francisco,因此引用了变量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用大括号括起来,因此我们能够对变量进行两次声明。


快速回顾:

  • 您可以将“作用域链”视为对我们可以在当前上下文中访问的值的引用链。
  • 作用域可以让我们重复使用外部作用域里的变量

范围(链)就是这样!关于这一点,还有很多话要说,所以我会在空闲时间添加一些额外的信息。如果您遇到任何困难,请随时提出问题,我很乐意提供帮助!💕

原文

个人博客

github.com/abc-club/fr…