javascript 中 var 声明变量的主要坑在于它没有块级作用域,且存在变量提升和重复声明覆盖的问题。这意味着在 if 或 for 等代码块内部定义的 var 变量会泄漏到外部作用域,且在循环中闭包捕获的往往是同一个变量引用而非当时的值。要解决这些问题,应使用 let 或 const 替代 var,它们提供了真正的块级作用域。

var 在循环中的闭包陷阱是什么
var 在循环中的闭包陷阱是指循环结束后,所有闭包函数引用的都是同一个变量实例,导致获取到的值总是循环结束后的最终状态,而不是循环执行时的瞬时值。这是因为 var 只有函数作用域,没有块级作用域,循环体内的变量声明会被提升到包含该循环的函数或全局作用域的顶部。要解决这个问题,可以使用 let 声明循环变量,或者使用 IIFE(立即调用函数表达式)为每次迭代创建独立的作用域。

function demonstrateVarLoopTrap() {
var funcs = [];
// 创建一个包含三个函数的数组
for (var i = 0; i < 3; i++) {
// 每个函数都引用同一个 var i
funcs.push(function() {
console.log("Index: " + i);
});
}
// 执行所有函数
for (var j = 0; j < funcs.length; j++) {
funcs[j]();
}
}
demonstrateVarLoopTrap();
// 预期输出:
// Index: 3
// Index: 3
// Index: 3
var 的变量提升会导致什么时序问题
var 的变量提升会导致在变量声明之前访问该变量时得到 undefined 而非报错,这容易引发难以排查的逻辑错误。变量提升意味着 JavaScript 引擎会将 var 声明移动到当前作用域的顶部,但初始化仍留在原地。如果在声明前就尝试读取该变量,会得到未初始化的默认值 undefined。这种隐式的提前声明行为使得代码的执行顺序变得不直观,尤其是在复杂的函数嵌套中。使用 let 可以避免这种情况,因为 let 声明的变量存在暂时性死区(TDZ),在声明前访问会直接抛出 ReferenceError。
立即学习“Java免费学习笔记(深入)”;

function demonstrateHoisting() {
console.log(x); // 输出 undefined,而不是 ReferenceError
var x = 10;
console.log(x); // 输出 10
}
demonstrateHoisting();
function demonstrateLetTDZ() {
try {
console.log(y); // 抛出 ReferenceError: Cannot access 'y' before initialization
} catch (e) {
console.log("Caught error: " + e.message);
}
let y = 20;
}
demonstrateLetTDZ();
在全局作用域中使用 var 会污染哪个对象
在全局作用域中使用 var 声明的变量会成为全局对象(在浏览器中是 window,在 Node.js 中是 global)的属性。这意味着通过 window.varName 可以直接访问这些变量,并且可以通过 delete window.varName 删除它们。这种行为容易导致命名冲突,特别是当多个脚本文件加载时,可能会意外覆盖已有的全局属性。相比之下,使用 let 或 const 在全局作用域声明的变量不会成为全局对象的属性,从而避免了这种污染。


















