代码示例
// 使用let
function letClosureExample() {
let values: number[] = [];
for (let i = 0; i < 3; i++) {
values.push(() => i);
}
return values;
}
// 使用const
function constClosureExample() {
let values: (() => number)[] = [];
for (let j = 0; j < 3; j++) {
const k = j;
values.push(() => k);
}
return values;
}
// 测试letClosureExample
let letFuncs = letClosureExample();
letFuncs.forEach((func, index) => {
console.log(`let闭包结果 ${index}:`, func());
});
// 测试constClosureExample
let constFuncs = constClosureExample();
constFuncs.forEach((func, index) => {
console.log(`const闭包结果 ${index}:`, func());
});
不同行为及原因
- let:
- 在
letClosureExample
中,for
循环内使用let
声明i
。let
声明的变量在块级作用域内有效,并且每次循环迭代时,i
会创建一个新的块级作用域实例。当将函数() => i
推入数组时,每个函数捕获的是对应迭代时i
的特定实例。所以,调用这些函数时,会输出0
、1
、2
。
- const:
- 在
constClosureExample
中,for
循环内使用const
声明k
。虽然const
声明的变量也是块级作用域,但它一旦声明就不能重新赋值。在每次循环迭代时,k
捕获的是当前迭代的j
的值。因为const
的特性,它不会像let
那样因为循环迭代而创建新的实例,而是在块级作用域内保持初始值。所以,每个闭包函数捕获的是当时k
的固定值,调用这些函数时,同样会输出0
、1
、2
。
实际开发中的潜在影响
- let:
- 优势在于处理需要在循环中创建多个独立状态的场景,例如创建多个定时器,每个定时器需要捕获不同的迭代值。
- 劣势是如果不小心,可能会因为块级作用域内变量的重新声明和修改导致难以调试的错误。
- const:
- 优势在于可以明确表明变量值不会改变,增强代码的可读性和可维护性,尤其在捕获不变的值用于闭包时。
- 劣势是如果在需要更新值的场景下使用
const
,会导致语法错误,需要开发者仔细考虑是否需要可变的变量。