ES6 标准化入门笔记--let 和 const 命令

一、let命令:

1.用于声明变量。用法类似于var,但是let声明的变量只在let命令所在的代码块内有效;

2.不存在变量提升。

var命令回出现“变量提升”现象,即变量可以在声明之前使用,值为undefined。

let声明的变量一定要在声明后使用,否则会报错。

3.暂时性死区。

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

var tmp = 123;

if (true) {
  tmp = 'abc'; // ReferenceError
  let tmp;
}

上面代码中,存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。

如果区块中存在let和const命令,则这个区块对这些命令声明的变量从一开始就形成封闭作用域。只要在声明前使用这些变量,就会报错;“暂时性死区”(temporal dead zone,简称TDZ);

4.不允许重复声明

二、块级作用域

1.没有块级作用域,会导致很多场景不合理:

  • 内层变量可能会覆盖外层变量;
  • 用来技术的循环变量泄露为全局变量;

2.ES6的块级作用域:

  • ES6 允许块级作用域的任意嵌套;
  • 外层作用域无法读取内层作用域的变量;
  • 内层作用域可以定义外层作用域的同名变量;
  • 块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了;

3.块级作用域与函数声明:

// 情况一
if (true) {
  function f() {}
}

// 情况二
try {
  function f() {}
} catch(e) {
  // ...
}
  • ES5规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。原则上上面两种函数声明在ES5中都是非法的。但是浏览器为了兼容以前的旧代码,所以上面两种情况实际上都能运行,并不会报错。
  • ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。在块级作用域之中,函数声明语句的行为类似于let在块级作用域之外不可引用
// 第一部分
function f() { console.log('I am outside!'); }

(function () {
  if (false) {
    // 重复声明一次函数f
    function f() { console.log('I am inside!'); }
  }

  f();
}());

// 第二部分---ES5 环境
function f() { console.log('I am outside!'); }

(function () {
  function f() { console.log('I am inside!'); }
  if (false) {
  }
  f();
}());

注意:

  • 上面第一部分代码在 ES5 中运行,会得到“I am inside!”,因为在if内声明的函数f会被提升到函数头部,实际执行的是第二部分的代码。
  • ES6 就完全不一样了,理论上会得到“I am outside!”。因为块级作用域内声明的函数类似于let,对作用域之外没有影响。但是,如果你真的在 ES6 浏览器中运行一下上面的代码,是会报错的。

        原因是:如果改变了块级作用域内声明的函数的处理规则,显然会对老代码产生很大影响。为了减轻因此产生的不兼容问题,ES6                            规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式。

                       -----允许在块级作用域内声明函数。

                       -----函数声明类似于var,即会提升到全局作用域或函数作用域的头部。

                       -----同时,函数声明还会提升到所在的块级作用域的头部。

上面三条规则只对 ES6 的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理。

根据这三条规则,在浏览器的 ES6 环境中,块级作用域内声明的函数,行为类似于var声明的变量。

// 第一部分----浏览器的 ES6 环境
function f() { console.log('I am outside!'); }

(function () {
  if (false) {
    // 重复声明一次函数f
    function f() { console.log('I am inside!'); }
  }

  f();
}());
// Uncaught TypeError: f is not a function


// 第二部分----浏览器的 ES6 环境
function f() { console.log('I am outside!'); }
(function () {
  var f = undefined;
  if (false) {
    function f() { console.log('I am inside!'); }
  }

  f();
}());
// Uncaught TypeError: f is not a function

三、const 命令

1.声明常量,一旦声明,就必须立即初始化,不能留到以后赋值且不可改变;

2.只在声明所在的块级作用域内有效;

3.声明的常量不提升,存在暂时性死区,只能在声明后使用;

4.const声明的常量,也与let一样不可重复声明。

注意:

  • const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动;
  • 对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量;
  • 但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。
const foo = {};

// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123

// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only

上面代码中,常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。

四、ES6 声明变量的六种方法

ES5 只有两种声明变量的方法:var命令和function命令。ES6 除了添加letconst命令,后面章节还会提到,另外两种声明变量的方法:import命令和class命令。所以,ES6 一共有 6 种声明变量的方法。

 

 

 

 

 

 

你可能感兴趣的:(js,es6,ES6标准入门)