var
-
使用var声明的变量是全局变量,且在预编译环节会提升至顶部(变量提升)
console.log(a); // -> undefined var a = 3; console.log(window.a); // -> 3 -
var可以重复声明,后面的会覆盖前面的
var b = 1; var b = 2; console.log(b); // -> 2
let
-
let声明的变量不存在变量提升的机制,也就是没有声明就不可以调用(暂时性死区)。
console.log(foo); // ReferenceError let foo = 2; -
let声明的变量有了块级作用域的概念,{}就是一个块。ES6之前只有全局作用域和函数作用域,导致很多的场景不可理, 内部变量会覆盖外层同名变量,for循环的变量泄漏为全局变量。
function test () { let a = 'outer'; if(true){ let a = 'inner'; console.log(a); // -> 'inner' } console.log(a); // -> 'outer' } test(); for(let i = 0; i < 3; i++){ console.log(i); // -> 0 1 2 } console.log(i); // ReferenceError: i is not defined
注:在for循环这里有一个特别之处,在设置循环变量的时候相当于一个父级作用域,在循环体中是一个单独的子作用域,let 的本质就是形成一个块级作用域。
for(let i = 0; i < 3; i++){
let i = 'a';
console.log(i) // -> 会打印三次 'a'
}
for(let i = 0; i < 3; i++){
i = 'a';
console.log(i); // -> 只打印一次 'a'
}
-
let在同一作用域下不可以重复声明
function fn () { let a = 1; let a = 2; } // SyntaxError: Identifier 'a' has already been declared
const
-
const声明一个只读的常量,一旦声明,必须立即初始化且常量的值不会改变。
const id = 33; id = 44; // 报错 TypeError: Assignment to constant variable. -
如果定义的是引用类型的值呢?
const foo = {}; foo = {name: "jerome", age: "22"}; console.log(foo); // 报错 foo.name = 'jerome'; foo.age = '22'; console.log(foo); // {name: "jerome", age: "22"} -
得出结论如果是引用类型的值 const 只会保证变量指向的内存地址不变,而不是变量的值不可改。
注:对象的值不可改(冻结对象)可以用 Object.freeze();
总结:
const 与 let 一样不存在变量提升、具有块级作用域、存在暂时性死区、不允许重复声明。还有const 与 let 声明的变量不会挂载到顶层对象(window 浏览器环境)上。