按照前端技术趋势发展,一些顶级的前端框架如国内比较火的vue已经使用ES6语法,vue3还会使用TypeScript,所以技术升级势在必行,接下来的一段时间我会整理学习常用的ES6技术系列文章。为什么不说JavaScript,因为这是是Oracle公司的注册商标!要说ECMScript,ECMS是European computer manufactures association(欧洲计算机制造联合会)缩写。

ES2015(ES6) 新增加了两个重要的 JavaScript 关键字: letconst

  • let 声明的变量只在 let 命令所在的代码块内有效。
  • const 声明一个只读的常量,一旦声明,常量的值就不能改变。

一、let命令

基本用法:

{
  let a = 0;
  a //0
}
a //报错 ReferenceError: a is not defined

相较于以前使用的varlet是在代码块内有效,而var是在全局范围内都有效。

let命令具有以下特性:

  • let 命令关键词声明的变量不具备变量提升(hoisting)特性;
  • 只在最靠近的一个块中(花括号内)有效;
  • 不能重复声明;
  • 暂时性死区;

特性示例:

{
    a //报错 Cannot access 'a' before initialization
    let a = 0; 
    let a = 1; //报错 Identifier 'a' has already been declared
}
a //报错 a is not defined

暂时性死区示例:

var tmp = 123;

if (true) {
    tmp = 'abc'; //报错 Cannot access 'tmp' before initialization
    let tmp;
}

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

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

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

总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

let命令特别适合在for循环中使用:

for (var i = 0; i < 10; i++) {
  setTimeout(function(){
    console.log(i);
  })
}
// 输出十个 10
for (let j = 0; j < 10; j++) {
  setTimeout(function(){
    console.log(j);
  })
}
// 输出 0123456789

变量i是用var声明的,在全局范围内有效,所以全局中只有一个变量i,每次循环时,setTimeout定时器里面的i指的是全局变量i,而循环里的十个setTimeout是在循环结束后才执行,所以此时的i都是10

变量j是用let声明的,当前的j只在本轮循环中有效,每次循环的j其实都是一个新的变量,所以setTimeout定时器里面的j其实是不同的变量,即最后输出 12345。(若每次循环的变量j都是重新声明的,如何知道前一个循环的值?这是因为 JavaScript 引擎内部会记住前一个循环的值)。

二、const命令

const用来声明一个只读常量,声明之后不允许改变。意味着,一旦声明必须初始化,否则会报错。

基本用法:

const PI = "3.1415926";
PI  // 3.1415926

const MY_AGE;  //报错 Missing initializer in const declaration

const命令具有以下特性:

  • 用来声明常量,常量的值不能改变,声明时必须被赋值;
  • 只在声明所在的块级作用域内有效;
  • const 命令声明的常量也是不提升(hoisting);
  • 当使用常量 const 声明时,请使用大写变量,如:UNAUTHORIZED
  • 暂时性死区;

特性示例:

const UNAUTHORIZED = '401';
UNAUTHORIZED  //401
UNAUTHORIZED = 500; //报错 Assignment to constant variable.

const SUCCESS;  //报错 Missing initializer in const declaration.

{
    ID_CARD //报错 Cannot access 'ID_CARD' before initialization
    const ID_CARD = '110xxx123';
    ID_CARD //110xxx123
}
ID_CARD //报错 ID_CARD is not defined

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

{
    const ARR = [1,2];
    ARR.push(3);
    ARR; // [1,2,3]
    ARR = 10; // Assignment to constant variable.
}

上面代码中,常量ARR存储的是一个地址,这个地址指向一个数组,数组本身是可写的,但如果将另一个数值赋值给ARR就会报错,如果想将复杂类型数据冻结,可使用object.freeze方法。

{
    const ARR = Object.freeze([1,2]);
    ARR.push(3); //报错 Cannot add property 2, object is not extensible
}

参考文章:


echeverra
44 声望14 粉丝