文章目录
- 什么是词法作用域?
- 示例1:全局作用域和局部作用域
- 示例2:闭包与词法作用域
- 示例3:动态创建函数与词法作用域
- 词法作用域 vs 动态作用域
什么是词法作用域?
词法作用域是指在 JavaScript 中,变量的作用域是由它们在代码中的位置决定的。这意味着在编写代码时,我们可以通过查看代码来确定每个变量的作用域,而不是等到程序运行时才确定。
示例1:全局作用域和局部作用域
让我们通过一个简单的示例来理解词法作用域:
var globalVar = 'I am global'; // 全局变量
function outer() {
var outerVar = 'I am outer'; // 外部函数的局部变量
function inner() {
var innerVar = 'I am inner'; // 内部函数的局部变量
console.log(innerVar); // 输出:I am inner
console.log(outerVar); // 输出:I am outer
console.log(globalVar); // 输出:I am global
}
inner();
}
outer();
console.log(globalVar); // 输出:I am global
console.log(outerVar); // 报错:outerVar is not defined
console.log(innerVar); // 报错:innerVar is not defined
在这个示例中,globalVar 是一个全局变量,在任何地方都可以被访问到。outerVar 是外部函数 outer 的局部变量,在 outer 函数内部可以被访问到,但在函数外部则无法访问。同样,innerVar 是内部函数 inner 的局部变量,只能在 inner 函数内部访问到。
示例2:闭包与词法作用域
闭包是 JavaScript 中的一个重要概念,它与词法作用域密切相关。让我们看一个闭包的例子:
function greet(name) {
var greeting = 'Hello';
function sayHello() {
console.log(greeting + ', ' + name);
}
return sayHello;
}
var greetJohn = greet('John');
var greetJane = greet('Jane');
greetJohn(); // 输出:Hello, John
greetJane(); // 输出:Hello, Jane
在这个例子中,greet 函数返回了一个内部函数 sayHello,并且这个内部函数可以访问外部函数 greet 中的变量 greeting 和 name。当我们将 greet 函数分别传入 ‘John’ 和 ‘Jane’ 作为参数后,我们得到了两个新的函数 greetJohn 和 greetJane,它们分别可以输出 ‘Hello, John’ 和 ‘Hello, Jane’。这就是闭包利用词法作用域的机制。
示例3:动态创建函数与词法作用域
动态创建函数时,它们的作用域仍然由词法作用域决定。让我们看一个动态创建函数的例子:
function createFunction() {
var dynamicVar = 'I am dynamic';
return function() {
console.log(dynamicVar);
};
}
var dynamicFunction = createFunction();
dynamicFunction(); // 输出:I am dynamic
在这个例子中,createFunction 函数返回了一个内部函数,并且这个内部函数可以访问外部函数 createFunction 中的变量 dynamicVar。即使 dynamicFunction 是在外部函数执行后创建的,它仍然可以访问外部函数中的变量,这是因为 JavaScript 中的函数作用域是词法作用域。
词法作用域 vs 动态作用域
与词法作用域相对应的是动态作用域。在动态作用域中,作用域是根据函数的调用堆栈动态变化的。这意味着函数可以访问调用它的函数的变量,而不是它定义的地方的变量。
JavaScript 使用词法作用域,这意味着在编写代码时,我们可以清楚地知道每个变量的作用域,这有助于我们更好地组织和调试代码。