JavaScript ES6 新增特性整理 - 1.新增语法特性

 2016年09月10日    222     声明


在ECMAScript 2015(ES6)语言标准中,扩展了一些新的语法特性,这些语法特性使JavaScript语言更加规范化,让语言使用也更加便捷。如:新增的块级变量及常量定义方式,弥补了原有一些语言缺陷;解构赋值可以更方便的从数组或对象中提取值。

  1. 变量常量定义
  2. 解构赋值
  3. for…of循环
  4. 展开(...)语法

1. 变量常量定义

1.1 let与块级变量声名

ES6 发布之前,JavaScript只能使用var来定义变量。但通过var定义的变量是全局的或是函数级的,在语句块内定义的变量,可以全局访问:

for (var i = 0; i < 5; i++) {
  var myVar = 'itbilu.com';
}

console.log(i);  // 5
console.log(myVar);  // 'itbilu.com'

let只能在严格模式下使用,其定义变量的方式与var类似,可以定义一个或多个变量,可以对定义的变量赋值或不赋值。但其与var定义的变量有以下两点区别:

  • let定义变量是块级的,而var定义的变量是全局的
  • let不能定义名称重复的变量,重复定义会引发TypeError错识

如,使用let定义块级变量:

'use strict'

for (let i = 0; i < 5; i++) {
  let myVar = 'itbilu.com';
}

console.log(i);  // ReferenceError: i is not defined
console.log(myVar);  // ReferenceError: myVar is not defined


1.2 const与常量声名

ES6 中还新增了定义常量的方式,定义一个常量使用const关键字。常量定义有以下特点:

  • 定义常量的同时必须对其初始化,否则会抛出SyntaxError异常
  • 常量定义后,不能对其重新赋值,否则会抛出TypeError异常
  • 常量名不能与其它常量、变量名称重复,否则会抛出SyntaxError异常

如,常量的使用:

// 常量名可以是大写或小写形式,但在习惯上使用大写定义
const MY_FAV = 7;
// 对常量重新赋值时会发生TypeError
MY_FAV = 20;   //TypeError

// 定义重复的常量名或变量名时会发生SyntaxError错误
const MY_FAV2 = 20; //SyntaxError
var MY_FAV2 = 20; //SyntaxError

//常量声明时,必须同时对其初化,否则会发生SyntaxError错误
const FOO; // SyntaxError


2. 解构赋值

解构赋值(Destructuring assignment)是ES6 新增的一种JavaScript表达语法。解构赋值使得从数组或者对象中提取数据,并赋值给不同的变量成为可能。

解构赋值是从对象字面量数组字面量中提取数据的便捷方式,解构赋值的有一个特别有用的功能是:可以用一个表达式读取整个结构。

var [a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2

var [a, b, ...rest] = [1, 2, 3, 4, 5]
console.log(a); // 1
console.log(b); // 2
console.log(rest); //[3,4,5]

var {a, b} = {a:1, b:2};
console.log(a); // 1
console.log(b); // 2

{a, b, ...rest} = {a:1, b:2, c:3, d:4}  
//ES7 

2.1 解构数组

以下是从数组字面量中解构赋值的一些使用示例:

简单示例

var foo = ["one", "two", "three"];

// 非解构赋值
var one   = foo[0];
var two   = foo[1];
var three = foo[2];

// 解构赋值
var [one, two, three] = foo;

变量交换

解构赋值可以让我们在不定义监时变量的情况下,交换两个变量的值:

var a = 1;
var b = 3;

[a, b] = [b, a];

返回多个值

使用解构赋值,使我们可以用类似数组的方式,返回多个变量:

function f() {
  return [1, 2];
}
// 解构式返回
var a, b;
[a, b] = f();

// 数组式返回
var arr = f();

选择性提取

通过解构赋值返回值时,可以忽略部分不需要的值:

function f() {
  return [1, 2, 3];
}

var [a, , b] = f();
console.log("A是 " + a + ",B是 " + b); // A是 1,B是3

或者使用正则表达式提取所需要的部分:

var url = "http://itbilu.com/nodejs/core";

var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
var [, protocol, fullhost, fullpath] = parsedURL;

console.log(fullhost); // 'itbilu.com'


2.2 解构对象

解构对象与解构数组使用类似,二者也可以混合使用。以下是从对象字面量中解构赋值的一些使用示例:

简单示例

var o = {p: 42, q: true};
var {p, q} = o;

console.log(p); // 42
console.log(q); // true 

// 用新变量名赋值
var {p: foo, q: bar} = o;

console.log(foo); // 42
console.log(bar); // true  

对象属性与解构

在计算对象属性名时,可以使用解构:

let key = "z";
let { [key]: foo } = { z: "bar" };

console.log(foo); // "bar"

参数默认值

ES6 通过解构对象,实现了函数参数默认值:

function post({url:'itbilu.com', port:80, data:{content:''}}) {
  console.log(url, port, data);
  // 一些操作
}
post({
  data:{
    title:'文章的标题', 
    content:'文章的内容'
  }
};)

模块加载

ES6 中定义了模块机制,在使用import关键字导入模块时,同样支持使用解构。

如,定义my-module模块:

// "my-module.js" 模块
export function cube(x) {
  return x * x * x;
}
const foo = Math.PI + Math.SQRT2;
export { foo };

导入模块,并使用解构赋值:

import { cube, foo } from 'my-module';
console.log(cube(3)); // 27
console.log(foo);    // 4.555806215962888

for…of迭代与解构

解构同样能在for…of迭代中使用:

var sites = [
  {
    name: "IT笔录",
    introduce: {
      domain: "itbilu.com",
      title: "IT笔录"
    }
  },
  {
    name: "老聂的小站",
    introduce: {
      domain: "niefengjun.cn",
      title: "聂峰军,聂峰军个人博客"
    }
  },
  {
    name: "一介布衣",
    introduce: {
      domain: "yijiebuyi.com",
      title: "一介布衣,专注 javascript 全栈开发"
    }
  }
];

for (var {name: n, introduce: { title: t, domain: url } } of sites) {
  console.log("name: " + n + ", title: " + t + ", url: " + url);
}


3. for…of循环

在ES5中我们可以全用for…in结构,来遍历一个数组结构。通过for…in循环可以获取数组索引,而ES6新增的for…of可以直接遍历获取数组值:

let iterable = [10, 20, 30];

for (let idx in iterable) {
  console.log(idx);   // 依次输出:0, 1, 2
}

for (let value of iterable) {
  console.log(value);   // 依次输出:10, 20, 30
}


4. 展开(...)语法

Spread语法在用于表达的某处展开,展开语法使用...符号表示。要展开的内容可能是多个函数参数(函数调用中)、多个元素(数组字面量)或多个变量(解构赋值中)。

语法结构为:

// 函数调用
myFunction(...iterableObj);

// 数组字面量
[...iterableObj, 4, 5, 6]

在函数调用中使用

在 ES6 之前,我们会使用Function.prototype.apply方法来将一个数组展开成多个参数:

function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction.apply(null, args);

通过 ES6 中的...运算符,我们可以这样写:

function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction(...args);

也可以同时展开多个数组参数:

function myFunction(v, w, x, y, z) { }
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);

在数组字面量中使用

...运算符让数组操作更加方便,我们可以很简单的通过一个已存在的数组构建一个新数组:

var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes']; // ["head", "shoulders", "knees", "and", "toes"]

在解构赋值中使用

在解构赋值时,同样可以使用...运算符:

var a, b, rest;
[a, b, ...rest] = [1, 2, 3, 4, 5];
console.log(a); // 1
console.log(b); // 2
console.log(rest); // [3, 4, 5]