JavaScript 中的作用域指的是变量、函数和对象的可访问范围。主要有以下几种作用域:
在任何函数外部定义的变量拥有全局作用域,可以在代码的任何地方访问。
var globalVar = "我是全局变量";
function test() {
console.log(globalVar); // 可以访问
}
test();
console.log(globalVar); // 也可以访问
在函数内部定义的变量只能在函数内部访问。
function test() {
var localVar = "我是局部变量";
console.log(localVar); // 可以访问
}
test();
console.log(localVar); // 报错: localVar is not defined
使用 let
和 const
声明的变量具有块级作用域,只在声明它们的块或子块中可用。
if (true) {
let blockVar = "我是块级变量";
console.log(blockVar); // 可以访问
}
console.log(blockVar); // 报错: blockVar is not defined
当查找变量时,JavaScript 会从当前作用域开始,逐级向上查找,直到找到变量或到达全局作用域。
var a = 1;
function outer() {
var b = 2;
function inner() {
var c = 3;
console.log(a + b + c); // 6 (可以访问所有变量)
}
inner();
console.log(a + b); // 3 (不能访问c)
}
outer();
console.log(a); // 1 (不能访问b和c)
闭包是指有权访问另一个函数作用域中的变量的函数。简单来说,当一个函数嵌套在另一个函数中,内部函数可以访问外部函数的变量,即使外部函数已经执行完毕。
function outer() {
var outerVar = "外部变量";
function inner() {
console.log(outerVar); // 访问外部函数的变量
}
return inner;
}
var closure = outer();
closure(); // 输出: "外部变量"
function counter() {
var count = 0;
return {
increment: function() {
count++;
return count;
},
decrement: function() {
count--;
return count;
},
getCount: function() {
return count;
}
};
}
var myCounter = counter();
console.log(myCounter.increment()); // 1
console.log(myCounter.increment()); // 2
console.log(myCounter.decrement()); // 1
console.log(myCounter.getCount()); // 1
// 有问题的方式
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i); // 全部输出5
}, 1000);
}
// 使用闭包解决
for (var i = 0; i < 5; i++) {
(function(j) {
setTimeout(function() {
console.log(j); // 输出0,1,2,3,4
}, 1000);
})(i);
}
// 使用let更简单(ES6)
for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i); // 输出0,1,2,3,4
}, 1000);
}
理解作用域和闭包是掌握 JavaScript 的关键,它们对于模块化开发、数据封装和许多设计模式都至关重要。