笨鸟理解
作用域不同:
var
: 函数作用域 (function-scoped)
在函数内部声明的变量只能在函数内部访问
如果在函数外或块语句(如if/for)中声明,则成为全局变量
示例:
function varTest() { var x = 1; if (true) { var x = 2; // 同一个变量 console.log(x); // 2 } console.log(x); // 2 } 以上代码可看出,虽然外部定义了 x = 1; 但由于在if内部定义了var x = 2; 所以最下方的console.log(x); 会输出 2 也就是说,var在循环/判断中定义的变量会溢出/影响到外面。
let
: 块级作用域 (block-scoped)
只在声明它的块或子块中有效
示例:
function letTest() { let x = 1; if (true) { let x = 2; // 不同的变量 console.log(x); // 2 } console.log(x); // 1 } 以上可看出,虽然let在内部定义了 x = 2; 但最终没有影响到外面的 x = 1;
变量提升 (Hoisting)
var
: 声明会被提升到作用域顶部,但初始化不会
可以在声明前访问,值为undefined
示例:
console.log(foo); // undefined var foo = 2; 在控制台中可以看到 foo 输出的值为 undefined
let
: 声明也会提升,但存在”暂时性死区”(TDZ)
在声明前访问会抛出ReferenceError
示例:
console.log(bar); // ReferenceError let bar = 2; 在控制台中可看到,直接抛出 ReferenceError 错误!
全局声明时的行为
var
: 在全局作用域声明会成为全局对象(浏览器中是window
)的属性
var x = 1; console.log(window.x); // 1 在控制台中可以看到输出内容是 1
let
: 不会成为全局对象的属性
let y = 2; console.log(window.y); // undefined 在控制台中可以看到输出的内容是 undefined 因为 let 是块级作用域,使用 let 声明的变量不会自动挂载到 window 对象上。 而 var 是函数作用域,会将变量挂载到 window 对象上
重复声明
var
: 允许在同一作用域内重复声明
var a = 1; var a = 2; // 允许
let
: 不允许在同一作用域内重复声明
let b = 1; let b = 2; // SyntaxError
实际使用建议:
-
优先使用
let
,它有更合理的作用域规则 -
只在需要函数作用域或特殊需求时使用
var
-
let
可以避免许多由变量提升和重复声明引起的问题 -
let
特别适合在循环中使用,避免闭包问题
总结表
特性 | var |
let |
---|---|---|
作用域 | 函数作用域 | 块级作用域 |
变量提升 | 是(初始化为undefined) | 是(但存在TDZ) |
重复声明 | 允许 | 不允许 |
全局属性 | 会成为window属性 | 不会成为window属性 |
循环中行为 | 可能有问题 | 表现符合预期 |