JavaScript 变量作用域

摘要:在本教程中,您将了解 JavaScript 变量作用域,它决定了变量的可见性和可访问性。

什么是变量作用域

作用域决定了变量的可见性和可访问性。JavaScript 有三种作用域

  • 全局作用域
  • 局部作用域
  • 块级作用域(从 ES6 开始)

全局作用域

当 JavaScript 引擎执行脚本时,它会创建一个全局执行上下文。

此外,它还会将您在函数外部声明的变量分配给全局执行上下文。这些变量位于全局作用域中。它们也被称为全局变量。

请查看以下示例

var message = 'Hi';Code language: JavaScript (javascript)

变量message 处于全局作用域中。它可以在脚本中的任何位置访问。

JavaScript Global Variables

局部作用域

您在函数内部声明的变量对该函数是局部的。它们被称为局部变量。例如

var message = 'Hi';

function say() {
    var message = 'Hello';
    console.log(message);
}

say();
console.log(message);
Code language: JavaScript (javascript)

输出

Hello
Hi

当 JavaScript 引擎执行say() 函数时,它会创建一个函数执行上下文。在say() 函数内部声明的变量message 被绑定到函数的函数执行上下文,而不是全局执行上下文。

JavaScript Local Variables

作用域链

请考虑以下示例

var message = 'Hi';

function say() {
    console.log(message);
}

say();
Code language: JavaScript (javascript)

输出

Hi

在此示例中,我们在say() 函数内部引用了变量message。在幕后,JavaScript 执行以下操作

  • say() 函数的当前上下文(函数执行上下文)中查找变量message。它没有找到任何匹配项。
  • 在外部执行上下文(即全局执行上下文)中查找变量message。它找到了变量message

JavaScript 解析变量的方式是先查看其当前作用域,如果找不到该变量,它会向上查找外部作用域,这被称为作用域链。

JavaScript Scope Chain

更多作用域链示例

请考虑以下示例

var y = 20;

function bar() {
    var y = 200;

    function baz() {  
        console.log(y);
    }

    baz();
}

bar();
Code language: JavaScript (javascript)

输出

200

在此示例中

  • 首先,JavaScript 引擎在baz() 函数的作用域中查找变量 y。它没有找到任何匹配项。因此,它移出该作用域。
  • 然后,JavaScript 引擎在bar() 函数中查找变量 y。它可以在bar() 函数的作用域中找到变量 y,因此它停止搜索。

全局变量泄漏:JavaScript 的怪异之处

请查看以下示例

function getCounter() {
    counter = 10;
    return counter;
}

console.log(getCounter());Code language: JavaScript (javascript)

输出

10

在此示例中,我们在没有varletconst 关键字的情况下将 10 分配给counter 变量,然后将其返回。

在函数外部,我们调用了getCounter() 函数并在控制台中显示了结果。

此问题被称为全局变量泄漏。

在幕后,JavaScript 引擎首先在getCounter() 函数的局部作用域中查找counter 变量。由于没有varletconst 关键字,因此counter 变量在局部作用域中不可用。它尚未创建。

然后,JavaScript 引擎遵循作用域链并在全局作用域中查找counter 变量。全局作用域也没有counter 变量,因此 JavaScript 引擎在全局作用域中创建了counter 变量。

要修复此“怪异”行为,您可以在脚本顶部或函数顶部使用'use strict'

'use strict'

function getCounter() {
    counter = 10;
    return counter;
}

console.log(getCounter());Code language: JavaScript (javascript)

现在,代码会抛出一个错误

ReferenceError: counter is not definedCode language: JavaScript (javascript)

以下是如何在函数中使用'use strict' 的示例

function getCounter() {
    'use strict'
    counter = 10;
    return counter;
}

console.log(getCounter());Code language: JavaScript (javascript)

块级作用域

ES6 提供了letconst 关键字,允许您在块级作用域中声明变量。

通常,只要您看到花括号{},它就是一个块。它可以是ifelseswitch 条件或fordo whilewhile 循环内的区域。

请查看以下示例

function say(message) {
    if(!message) {
        let greeting = 'Hello'; // block scope
        console.log(greeting);
    }
    // say it again ?
    console.log(greeting); // ReferenceError
}

say();Code language: JavaScript (javascript)

在此示例中,我们在if 块外部引用了变量greeting,导致错误。

在本教程中,您学习了 JavaScript 变量作用域,包括函数作用域、全局作用域和块级作用域。

本教程对您有帮助吗?