探索ES6之 let 和 const

466 阅读3分钟

1.let命令

es6新增了let命令,用来声明变量,变量只在let所在的代码块内有效,很适合在for中使用,看例子

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

发现输出的跟预期不一致,是因为i是var声明的,属于全局变量,全局范围内只有一个变量i,每次循环i都会改变,所以运行到最后执行i++,所以输出10。用let就可以避免这种问题

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

for循环需要注意的是,设置循环变量的是一个父作用域,而循环体内部是独立的子作用域。

1.1 不存在变量提升

关于变量提升,可以参考www.lagou.com/lgeduarticl…

周知,var命令会变量提升,可以再声明之前使用,值为undefined。let纠正了这种语法,它所声明的变量一定要在声明后使用,否则报错。

1.2 暂时性死区(TDZ)

如果区块中存在let,const命令,这个区块就对这些命令声明的变量封闭,凡是在声明之前使用,都会报错。

var tmp = 123;
if (true) {
  tmp = 'abc'; // ReferenceError
  let tmp;
  console.log(tmp); // undefined
  tmp = 123;
  console.log(tmp); // 123
}

1.3 不允许重复声明变量

2 块级作用域

es5只有全局作用域和函数作用域,没有块级作用域,会带来一些问题,

var tmp = new Date();
function f() {
  console.log(tmp);
  var tmp = 'hello world';
}
f(); // undefined

上述,内层变量可能会覆盖外层变量。tmp原本是date对象,执行f()时,检测console的tmp在后又声明,所以tmp为undefined。

var s = 'hello';
for (var i = 0; i < s.length; i++) {
  console.log(s[i]);
}
console.log(i); // 5

上述,用来计数的变量,泄露为全局变量。 ES6的块级作用域 let为js新增了块级作用域,

function f1() {
  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); // 5
}

外层代码块不受内层代码块的影响。

ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。

疑问:let只能出现在当前作用域的顶层?严格模式下,函数只能声明在当前作用域的顶层?

3 const命令

const声明一个只读常量,一旦声明就不可以更改。const一旦声明变量,就必须立即初始化,不能留到以后赋值。作用域只在所在的块级作用域中有效 本质上,const保证的是变量指向的内存地址所保存的数据不可变动,对于简单数据类型,值就保存在变量指向的内存地址,但对于复合型数据类型,变量指向的内存地址,保存一个指向实际数据的指针,const只能保证指针是固定,不能保证他指向的数据结构是否可变。