The scope is the execution context of a variable or function. It defines what data it has access to. This concept may seem pretty straightforward, but has some important subtleties.
作用域是变量或函数的执行上下文。 它定义了它有权访问的数据。 这个概念可能看起来很简单,但是有一些重要的微妙之处。
JavaScript has traditionally had two types of scope: global scope and local scope. The purpose of the scope is to provide access to all variables and functions that an execution context has access to.
传统上,JavaScript具有两种类型的范围:全局范围和局部范围。 范围的目的是提供对执行上下文可以访问的所有变量和函数的访问。
全球范围 (Global Scope)
When a variable is declared outside of any function it belongs to the global scope automatically and can be accessed from anywhere in the program, be it a function or any block. Also, if desired, in the browser we can create a global variable by declaring it as window.newVariable
at any place in a program.
当变量在任何函数之外声明时,它将自动属于全局范围,并且可以从程序中的任何位置(无论是函数还是任何块)进行访问。 另外,如果需要,在浏览器中,我们可以通过在程序中的任何位置将其声明为window.newVariable
来创建全局变量。
const nestAnimal = 'crocodilian'; // belongs to the Global scope
function getNestInfo(){
window.eggs = 5; // as well belongs to the Global scope
}
In fact, in the browser, variables in the global scope belong to the global window
object.
实际上,在浏览器中,全局作用域中的变量属于全局window
对象。
JavaScript is a garbage-collected language, it keeps available all variables while executing the program in the context and remove after. Let’s consider the lifecycle of the variable. The variable comes into existence during the execution of the function. The variable is used inside the function and then the function ends. At that point this variable is no longer needed, so its memory can be reclaimed and JavaScript remove this variable from the memory. But global variables remain in the memory for the all the time the application is running and clogs up it, which slows down the program, also it may cause unexpected name conflicts.
JavaScript是一种垃圾收集的语言,它在上下文中执行程序时保留所有变量可用,之后将其删除。 让我们考虑变量的生命周期。 该变量在函数执行期间就存在。 该变量在函数内部使用,然后函数结束。 那时不再需要此变量,因此可以回收其内存,JavaScript会从内存中删除此变量。 但是,全局变量在应用程序运行期间一直保留在内存中并阻塞它,这减慢了程序的速度,还可能导致意外的名称冲突。
That all means that, whenever possible, you should avoid to defining global variables. They are only truly needed in very specific cases, so be careful with this.
这一切都意味着,只要有可能,就应避免定义全局变量。 仅在非常特定的情况下才真正需要它们,因此请务必小心。
当地范围 (Local Scope)
ES6 introduced block-scoped variables using the const
and let
keywords. With these keywords, local scope is created and exists within the innermost block that surrounds it. It could be a function, for
loop, while
block, if
block, etc. Such locally scoped variables can be only accessed from within that block.
ES6引入了使用const
和let
关键字的块范围变量。 使用这些关键字,将创建局部作用域,并将其存在于包围它的最里面的块中。 它可能是一个函数, for
循环, while
块, if
块等。只能在该块内部访问此类局部范围的变量。
Each block has its own execution context which defines what data it has access to, as well as how it should behave. When code is executed in a context, a scope chain is created. It includes all declared variables and functions inside that block, then the data from the containing (parent) context, and so on. This pattern continue until the global context is reached.
每个块都有其自己的执行上下文,该上下文定义了它可以访问的数据以及其行为方式。 在上下文中执行代码时,将创建作用域链。 它包括该块内的所有已声明的变量和函数,然后是包含(父)上下文的数据,依此类推。 这种模式一直持续到达到全局为止。
Let’s have a look at an example:
让我们看一个例子:
let caymanMood = 'calm';
function changeMood(newMood){
if (caymanMood === 'calm'){
caymanMood = newMood;
} else {
caymanMood = 'calm';
}
}
changeMood('happy');
The function changeMood
has a scope chain with two objects in it: its own variable object (arguments object newMood
) and the global context’s variable object caymanMood
. The function has access to caymanMood
because it’s part of its scope chain.
函数changeMood
具有一个包含两个对象的作用域链:它自己的变量对象(参数对象newMood
)和全局上下文的变量对象caymanMood
。 该函数可以访问caymanMood
因为它是其作用域链的一部分。
范围链增强 (Scope Chain Augmentation)
It’s possible to augment the scope chain besides global and local execution contexts. We can do this in two ways.
除了全局和本地执行上下文外,还可以扩展作用域链。 我们可以通过两种方式做到这一点。
Point 1: A with statement
第一点 :带有语句的A
Point 2: The
catch
block in atry...catch
statement.第二点 :
try...catch
语句中的catch
块。
function buildNest() {
const assets = 'grass';
with(reptilian){
const building = ability + assets;
}
return building;
}
with
creates a object that is added to the front of the scope chain, but the thing is when you read the code you can’t know for sure which object exactly will be modified. Will it be the global variable ability
or the variable in this context reptilian.ability
. So the correct execution of the program can’t be guaranteed. Use of the with
statement is not recommended by the MDN web docs as it may be a source of confusing bugs and compatibility issues.
with
创建一个对象,该对象被添加到作用域链的前端,但是问题是,当您阅读代码时,您无法确定确切地将修改哪个对象。 是全局变量ability
还是此上下文中的reptilian.ability
变量。 因此,不能保证程序的正确执行。 MDN Web文档不建议使用with
语句,因为它可能导致令人困惑的错误和兼容性问题。
The catch
statement creates a new variable object that contains a declaration for the thrown error object and this error object is added to the front of the scope chain.
catch
语句创建一个新的变量对象,该对象包含对抛出的错误对象的声明,并且此错误对象被添加到作用域链的前面。
结语 (Wrapping Up)
With this, you should now have a slightly better understanding of how local and global scope works in JavaScript and how relying on the closest local context possible is a good idea for writing easily readable and maintainable code.
这样,您现在应该对本地和全局作用域如何在JavaScript中工作以及如何尽可能依赖最接近的本地上下文有了更好的理解,这是编写易于阅读和可维护的代码的好主意。
翻译自: https://www.digitalocean.com/community/tutorials/js-variable-scope