Time for the scope chain 🕺🏼 In this post I assume you know the basics of execution contexts: I’ll soon write a post on that too though 😃
作用域 🕺🏼 在本文中,我假设您了解执行上下文的基础: 尽管如此,我也将很快就此发表一篇文章 😃
Let’s take a look at the following code:
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());
We’re invoking the getPersonInfo
function, which returns a string containing the values of the name
, age
and city
variables:Sarah is 22 and lives in San Francisco
. But, the getPersonInfo
function doesn’t contain a variable named city
🤨? How did it know the value of city
?
我们调用
getPersonInfo
函数,该函数返回一个包含name
,age
和city
变量的值:Sarah is 22 and lives in San Francisco
.但是,该getPersonInfo
函数不包含名为city
🤨 的变量.它怎么知道city
的值?
First, memory space is set up for the different contexts. We have the default global context (window
in a browser, global
in Node), and a local context for the getPersonInfo
function which has been invoked. Each context also has a scope chain.
首先,为不同的上下文设置存储空间.我们有默认的 全局上下文 (在浏览器中是
window
,在 node 是global
),以及局部上下文为getPersonInfo
已调用的功能.每个上下文也都有一个 作用域链.
For the getPersonInfo
function, the scope chain looks something like this (don’t worry, it doesn’t have to make sense just yet):
对于
getPersonInfo
函数,作用域链看起来像这样(不用担心,它现在还没有必要):
The scope chain is basically a “chain of references” to objects that contain references to values (and other scopes) that are referencable in that execution context. (⛓: “Hey, these are all the values you can reference from within this context”.) The scope chain gets created when the execution context is created, meaning it’s created at runtime!
作用域链基本上是对对象的”引用链”,这些对象包含对在该执行上下文中可引用的值(和其他作用域)的引用.(⛓: “嘿,这些都是您可以在此上下文中引用的所有值”.)作用域链是在创建执行上下文时创建的,这意味着它是在运行时创建的!
However, I won’t talk about the activation object or the execution contexts in general in this post, let’s just focus on scope! In the following examples, the key/value pairs in the execution contexts represent the references that the scope chain has to the variables.
但是,在本文中,我一般不会讨论激活对象或执行上下文,我们只关注作用域!在以下示例中,执行上下文中的键/值对表示作用域链对变量的引用.
The scope chain of the global execution context has a reference to 3 variables: name
with the value Lydia
, age
with the value 21
, and city
with the value San Francisco
. In the local context, we have a reference to 2 variables: name
with the value Sarah
, and age
with the value 22
.
全局执行上下文的作用域链引用了 3 个变量:
name
带有值Lydia
,age
带有值21
,city
带有值San Francisco
.在本地上下文中,我们引用了 2 个变量:name
带有值Sarah
和age
使用值22
.
When we try to access the variables in the getPersonInfo
function, the engine first checks the local scope chain.
当我们尝试访问该
getPersonInfo
函数中的变量时,引擎首先检查本地作用域链.
The local scope chain has a reference to name
and age
! name
has the value of Sarah
and age
has the value of 22
. But now, what happens when it tries to access city
?
本地作用域链引用了
name
和age
!name
的值为Sarah
,age
的值为22
.但是现在,当它尝试访问city
时会发生什么?
In order to find the value for city
the engine “goes down the scope chain”. This basically just means that the engine doesn’t give up that easily: it works hard for you to see if it can find a value for the variable city
in the outer scope that the local scope has a reference to, the global object in this case.
为了找到
city
的值, 引擎”必须深入作用域链中”.这基本上只是意味着引擎不会轻易放弃: 它会努力使您查看是否可以city
在局部作用域引用的外部作用域(在这种情况下为全局对象)中找到变量的值.
In the global context, we declared the variable city
with the value of San Francisco
, thus has a reference to the variable city
. Now that we have a value for the variable, the function getPersonInfo
can return the string Sarah is 22 and lives in San Francisco
🎉
在全局上下文中,我们
city
使用的值声明了变量San Francisco
,从而引用了该变量city
.现在我们有了变量的值,该函数getPersonInfo
可以返回字符串Sarah is 22 and lives in San Francisco
🎉
We can go down the scope chain, but we can’t go up the scope chain. (Okay this may be confusing because some people say up instead of down, so I’ll just rephrase: You can go to outer scopes, but not to more inner… (innerer..?) scopes. I like to visualize this as a sort of waterfall:
您可以使用外部作用域,但不能进入更内部…(内部…)作用域.我想形象地看到这一点.作为一种瀑布:
Or even deeper:
Let’s take this code as an example.
It’s almost the same, however there’s one big difference: we only declared city
in the getPersonInfo
function now, and not in the global scope. We didn’t invoke the getPersonInfo
function, so no local context is created either. Yet, we try to access the values of name
, age
and city
in the global context.
几乎一样,但是有一个很大的不同: 我们现在 在
getPersonInfo
函数中仅声明city
,而没有在全局作用域中声明.我们没有调用该getPersonInfo
函数,因此也没有创建本地上下文.然而,我们试图在全局作用域内访问name
,age
并city
的值.
It throws a ReferenceError
! It couldn’t find a reference to a variable called city
in the global scope, and there were no outer scopes to look for, and it cannot go up the scope chain.
它抛出
ReferenceError
!它在全局作用域内,找不到一个叫做city
变量的引用,并没有到外部作用域寻找,它不能上朔作用域链.
This way, you can use scope as a way to “protect” your variables and re-use variable names.
这样,您可以将作用域用作”保护”变量并重新使用变量名的方法.
Besides global and local scopes, there is also a block scope. Variables declared with the let
or const
keyword are scoped to the nearest curly brackets ({``}
).
除了全局和局部作用域之外,还有一个块作用域.用
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;
}
}
You can visualize the scopes as:
您可以将作用域可视化为:
We have a global scope, a function scope, and two block scopes. We were able to declare the variable message
twice, since the variables were scoped to the curly brackets.
我们有一个全局作用域,一个函数作用域和两个块作用域.
message
由于变量的作用域用大括号括起来,因此我们能够两次声明该变量.
To quickly recap:
- You can see “scope chain” as a chain of references to values that we can access in the current context.
- Scopes also make it possible to re-use variable names that were defined further down the scope chain, since it can only go down the scope chain, not up.
- 您可以将”作用域链”视为对我们可以在当前上下文中访问的值的引用链.
- 作用域还可以重用在作用域链下游定义的变量名称,因为它只能在作用域链中向下移动,而不能向上.
That was it for scope (chains)! There’s tons more to say about this so I may add extra info when I have some free time. Feel free to ask questions if you’re struggling with anything, I love to help! 💕
作用域(链)就是这样!关于这一点还有更多的话要说,所以当我有空闲时间时,我可能会添加更多信息.如果您遇到任何困难,请随时提出问题,我很乐意提供帮助!💕