let命令

基本用法

跟使用es5的var一样

BUT

不存在变量提升

var会存在变量提升现象,

letconst则不会有这种情况

暂时性死区 简称 TDZ

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

  1. var tmp = 123;
  2. if (true) {
  3. tmp = 'abc'; // ReferenceError
  4. let tmp;
  5. }

ES6 明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

不允许重复申明

let不允许在相同作用域内,重复声明同一个变量。

  1. // 报错
  2. function func() {
  3. let a = 10;
  4. var a = 1;
  5. }
  6. // 报错
  7. function func() {
  8. let a = 10;
  9. let a = 1;
  10. }

因此,不能在函数内部重新声明参数。

  1. function func(arg) {
  2. let arg; // 报错
  3. }
  4. function func(arg) {
  5. {
  6. let arg; // 不报错
  7. }
  8. }

块级作用域

为什么需要块作用域

ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。

第一种场景,内层变量可能会覆盖外层变量。

  1. var tmp = 123;
  2. function f() {
  3. console.log(tmp);
  4. if (false) {
  5. var tmp = 'hello world';
  6. }
  7. }
  8. f(); // undefined

第二种场景,用来计数的循环变量泄露为全局变量。

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

ES6 的块级作用域

  1. function f1() {
  2. let n = 5;
  3. if (true) {
  4. let n = 10;
  5. }
  6. console.log(n); // 5
  7. }

ES6 允许块级作用域的任意嵌套。

块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了。

  1. // IIFE 写法
  2. (function () {
  3. var tmp = ...;
  4. ...
  5. }());
  6. // 块级作用域写法
  7. {
  8. let tmp = ...;
  9. ...
  10. }

块级作用域不返回值,除非t是全局变量。

const

const声明一个只读的常量。

const除了以下两点与let不同外,其他特性均与let相同:

  1. const一旦声明变量,就必须立即初始化,不能留到以后赋值。
  2. 一旦声明,常量的值就不能改变。

本质

const限定的是赋值行为。

也就是说

  1. const a = 1;
  2. a = 2;//报错
  3. const arr = [];
  4. arr.push(1) //[1]
  5. //在声明引用型数据为常量时,const保存的是变量的指针,只要保证指针不变就不会保存。下面的行为就会报错
  6. arr = [];//报错 因为是赋值行为。变量arr保存的指针改变了。

顶层对象属性与全局变量

顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象。ES5 之中,顶层对象的属性与全局变量是等价的。

  1. window.a = 1;
  2. a // 1
  3. a = 2;
  4. window.a // 2

顶层对象的属性与全局变量挂钩,被认为是 JavaScript 语言最大的设计败笔之一。

为了解决这个问题,es6引入的letconstclass声明的全局变量不再属于顶层对象的属性。

而同时为了向下兼容,var和function声明的变量依然属于全局对象的属性

  1. var a = 1;
  2. window.a // 1
  3. let b = 1;
  4. window.b // undefined