javascript中的变量如何声明和赋值?【教程】

必须分清var、let、const的行为差异:const优先用于不重赋值的绑定,支持对象属性修改但禁止重绑定;let提供块级作用域和TDZ;var存在函数作用域和提升;隐式全局变量危险且应禁用。

JavaScript 中变量声明和赋值不是“选哪种更好”,而是“必须分清 varletconst 的行为差异”,否则会在作用域、重复声明、提升(hoisting)上踩坑。

什么时候该用 const 而不是 let

const 并不表示“值不可变”,而是“绑定不可重赋值”。只要不是立刻要重新赋值,就优先用 const —— 这能避免意外覆盖,也更利于静态分析。

  • 函数参数、对象字面量、数组、正则表达式等,只要不打算写 foo = ...,就用 const
  • const 声明必须初始化,const x; 会直接报 SyntaxError: Missing initializer in const declaration
  • 对象属性或数组元素仍可修改: const arr = [1]; arr.push(2); 合法;但 arr = []; 报错

letvar 在循环中表现完全不同

var 声明的循环变量在闭包中会捕获最后的值,而 let 每次迭代都绑定新绑定 —— 这是面试高频陷阱,也是实际异步回调出 bug 的根源。

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0); // 输出 3, 3, 3
}
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log(j), 0); // 输出 0, 1, 2
}
  • var 有函数作用域 + 变量提升,let/const 是块级作用域 + 暂时性死区(TDZ)
  • typeof myLetVar 在声明前会抛 ReferenceError,而 typeof myVar"undefined"

隐式全局变量是危险的快捷方式

不声明直接赋值(如 counter = 1)会创建隐式全局变量,即使在严格模式下也会报错 —— 它绕过了所有作用域控制,极易污染全局、引发冲突。

  • ESLint 规则 no-implicit-globalsno-undef 可捕获这类写法
  • 模块环境下(type="module" 或 ES module 文件),未声明赋值直接报 ReferenceError
  • 浏览器中顶

    this.counter = 1 看似等价,但语义混乱,不推荐

真正容易被忽略的是:constletiffortry 块内声明后,外部无法访问 —— 很多人以为“没报错就是能用”,结果在块外读取时得到 ReferenceError,而不是 undefined