var、let、const
1.let:声明变量,有块级作用域,不允许在同一作用域内重复声明,在不同作用域内可以重复声明,let不像var那样会发生“变量提升”现象。所以,变量一定要在声明后使用,否则报错。只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响(称为暂存死区),循环中的let作用域,注意浏览器兼容性。
2.var:声明变量和常量,没有块级作用域,var声明存在变量提升
3.const:声明一个只读的常量。一旦声明,常量的值就不能改变。也可用于声明对象,数组。
4.ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
例子:
// var 的情况
console.log(foo); // 输出undefined
var foo = 2;
// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
function test(){
{
var a = 1;
}
alert(a); a可以访问到alert出1
}
function test(){
{
let a = 1;
}
alert(a); a不能够被访问到alert报错,因为let具有块级作用域,只在let 声明的那个作用域内可以访问
}
function test(){
{
let a = 1;
let a = 2; 这样会报错在同一作用域下不能重复声明
}
alert(a); a不能够被访问到alert报错,因为let具有块级作用域,只在let 声明的那个作用域内可以访问
}
function test(){
let a = 3;
{
let a = 1;
let a = 2; 这样会报错在同一作用域下不能重复声明
}
alert(a); alert出3
}
function test(){
let a = 3; 会报错,因为let在同一作用域下不允许重复声明,而var没用块级作用域相当于在这个作用域声明了a
{
var a = 1; var没有块级作用域相当于在外面声明了一个a
}
alert(a);
}
function test(){
var a = 3; 不会报错
{
let a = 1; 这个let声明的a是在当前这个块级作用下的a,不受外面作用域下a的冲突影响
}
alert(a); alert出3
}
function test(){
let a = 3; 不会报错 因为a = 1 声明在全局 而let a = 3声明在function test()作用域下
{
a = 1; 没有声明符声明相当于在全局声明了一个a
}
alert(a); alert出3 就近原则 let a = 3 在函数作用域内
}
ps:以上实例所用let声明的a为常量所以正确应该全部改为使用const声明
对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址。const
命令只是保证变量名指向的地址不变,并不保证该地址的数据不变,所以将一个对象声明为常量必须非常小心。
const foo = {};
foo.prop = 123;
foo.prop// 123
foo = {}; // TypeError: "foo" is read-only
上面代码中,常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。
const a = [];
a.push('Hello'); // 可执行
a.length = 0; // 可执行
a = ['Dave']; // 报错
上面代码中,常量a是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给a,就会报错。
window.a = 1;
a // 1
a = 2;
window.a // 2
顶层对象,在浏览器环境指的是window对象,在Node指的是global对象。ES5之中,顶层对象的属性与全局变量是等价的。上面代码中,顶层对象的属性赋值与全局变量的赋值,是同一件事。
ES6为了改变这一点,一方面规定,为了保持兼容性,var命令和function
命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从ES6开始,全局变量将逐步与顶层对象的属性脱钩。
var a = 1;
// 如果在Node的REPL环境,可以写成global.a
// 或者采用通用方法,写成this.a
window.a // 1
let b = 1;
window.b // undefined
上面代码中,全局变量a由var命令声明,所以它是顶层对象的属性;全局变量b由let命令声明,所以它不是顶层对象的属性,返回undefined。
更详细参考阮一峰let和const