JavaScript 作用域
根据 MDN 的定义,JavaScript 中的“作用域”是指代码的当前执行上下文。这究竟是什么意思呢?作用域定义了当前可访问的变量和值,它也可以指变量的环境。让我们直接来看一个例子:
function hello(){
var phrase = "Hello";
console.log(phrase + " Dylan");
}
console.log(phrase);
我们有一个名为 hello() 的函数,并在函数内部定义了一个名为“phrase”的变量。如果我们尝试从函数外部访问变量“phrase”,将会收到以下错误:
Uncaught ReferenceError: phrase is not defined
这很容易理解,对吧?从全球视角来看,我们并不知道什么是“短语”。
但是,如果我们定义一个全局变量,并尝试在函数内部使用它:
var person = "Dylan"
function hello(){
var phrase = "Hello";
console.log(phrase + " "+ person);
}
hello()
我们将得到:
Hello Dylan
由此可知,作用域遵循层级结构,子层可以访问父层的变量,但反过来不行。
在上一篇文章(JavaScript:单线程但非阻塞)中,我们提到 JavaScript 引擎拥有函数执行上下文的调用栈。全局执行上下文创建时,也会引入全局变量环境。如果我们现在定义一个全局变量,该变量将被添加到全局对象(例如浏览器中的 window 对象)下。
每个执行上下文都有一个局部变量环境,称为局部作用域。如果我们尝试访问当前执行上下文中的一个变量,它会首先在局部作用域中查找该变量。如果找不到该变量,它会向上追溯到父作用域查找。这被称为作用域链。例如:
function func1(){
var a = 20;
return function func2(){
console.log(a);
}
}
var a = 10;
func1()();
在这个例子中,代码试图查找变量a,因为它在 func2 中使用。在 func2 的作用域内找不到 a 后,它会向上查找 func1 并找到了它(a = 20)。因此,控制台输出的结果为 20。
执行上下文的作用域链
如果我们把代码改成这样:
function func1(){
var a = 20;
return func2()
}
function func2(){
console.log(a);
};
var a = 10;
func1()
这次输出的是 10。这是为什么呢?我们需要引入另一个术语:词法作用域。词法作用域指的是函数定义的位置,而不是调用的位置。在第一个例子中,函数 func2 定义在 func1 内部,因此它会向上查找 func1 中缺失的变量,因为该变量不在其当前作用域内。然而,在第二个例子中,函数 func2 定义在全局作用域内(与 func1 处于同一级别),因此它会向上查找全局作用域来获取缺失的变量。
希望这篇文章能让你对 JavaScript 的作用域机制有个大致的了解。在以后的文章中,我还会介绍诸如提升、闭包、块级作用域等概念,以便让你更清楚地理解(本来应该在这篇文章里讲到的,但我太忙了,抱歉)。
请关注我,我会持续发布关于网页设计、编程和自我提升的文章😊
文章来源:https://dev.to/ohdylan/javascript-scoping-3adl

