ES6 笔记

2 minute read

解构赋值 Destructuring

从数组或对象中提取值,对变量进行赋值。以匹配结构形式,将数组或变量对应位置的值赋予对应结构位置的变量。 等号右边,必须是可遍历的数据结构。

let [a, ...b] = [1, 2, 3, 4]
a // 1
b // [2, 3, 4]

// 变量替换
let a = 1, b = 10;
[a, b] = [b, a];
a // 10
b // 1

// 对象结构
let  {baz, foo} = {baz: 'aaa', foo: 'bbb'};
baz // aaa
foo // bbb

const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }

Symbol

Symbol 是 ES6 扩展的第七种数据类型(另六种 undefined、null、Boolean、String、Number、Object)。 Symbol 每次调用生成一个独一无二的标识符,此类型不能隐式转换为字符串(不能与字符串类型相加),可显示转换(String 函数)。对象的 Symbol 类型的属性不能通过 Object.keys 或 for .. in 的方式遍历到,需 Object.getOwnPropertySymbols 获取。

let a = Symbol();
let b = Symbol();
a === b // false

// 可传人参数,当作 Symbol 的理解信息
let s1 = Symbol('foo');
let s2 = Symbol('bar');
console.log(s1 );
// Symbol(foo)

// 作为对象属性

let attr = Symbol();
let obj[attr] = 'Hello';

如何重复使用一个值

let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');

s1 === s2 // true

Symbol.iterator 将数组转化为一个迭代器

let arr = [1, 2, 3, 4, 5];
let it = arr[Symbol.iterator]();
it.next() // {value: 1, done: false}
it.next() // {value: 2, done: false}

Promise

Promise 是一种异步编程解决方案,作为容器组合了异步函数及其回调。异步函数作为参数传递给 Promise 构造函数完成实例化,同时 Promise 对象会提供两个可改变自己状态(成功 fulfilled 或失败 rejected)的方法(resolve 和 reject)给异步函数,一旦异步函数改变状态,Promise 会自动调用通过 then 、catch 等方法附加在其上的回调函数。

Promise 对象的特点

Promise 是一个 micro task,一旦新建就会立即执行,此时处于 pending 状态,无法取消,只有异步操作的结果可以改变对象为 fulfiled 或 rejected。

状态改变后,不再变化。此时再通过 then 向对象添加回调函数,会立即得到结果,与事件不同的时,事件错过了,再此添加监听,无法收到过去的事件。

使用流程

  1. 创建实例
  2. then 方法增加指定回调
const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

示例

const promise = new Promise(function(resolve, reject){
  console.log('first info');
  setTimeout(function() {
    resolve('OK');
  }, 1000);
});

promise.then(function(value){
  console.log('in then get: ' + value);
});

console.log('wait for ...');
// first info
// wait for ...
// in then get: OK

then 方法

then 方法用于为 Promise 实例添加状态改变时的回调函数,其定义在 Promise.prototype 上。then 方法接收的第一个参数为状态 resolve 后的回调函数,第二个参数可选,为状态 reject 后的回调函数。 then 方法调用结束后会返回一个新的 Promise 实例,因此可以采用链式写法,即 then 方法后面再调用另一个 then 方法。 如果上一个 then 方法接收的回调函数返回的是不是一个 Promise 对象,返回值将会作为结果传递给第二个回调函数。 内部错误不会抛出,catch 会吃掉内部产生的错误。

Promise.all([])

接收一个 promise 对象数组返回一个新的 promise 对象,所有的 promise 都 resolve 以后才会 resolve,否则 reject 如果有 promise reject 被捕获,仍会认为其 fulfiled,最后运行 resolve。

Promise.resolve() 将现有参数转化为 promise 对象

Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))

done 和 finally 区别,done 穿进去的函数不一定被执行

Generator

Generator 是一个状态机,封装了多个内部状态。函数调用后会返回一个遍历器对象,调用遍历器的next() 方法可以依次遍历函数的每个状态,每调用一次返回一个有 value 和 done(Boolean类型)的对象。 声明使用 function * ,定义内部状态使用 yeild 关键字修饰表达式, return 的结果也是一种状态。 每调用一次 next,内部指针就从函数头或上一次 yield 下来,直到遇到下一个 yield 或 return。

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}
var hw = helloWorldGenerator();
hw.next().value
  • next 可传入参数,作为函数内部 yield语句的返回值
  • for…of循环可以自动遍历 Generator 函数时生成的Iterator对象,且此时不再需要调用next方法。
  • return 后的值不会被遍历
  • next、throw、return 都可恢复执行
  • yield * 用来在一个 Generator 函数内部执行另一个 Generator 函数

async await ES2017

实现异步操作的方法,执行到 await 函数会交出执行权,等到结果返回后,继续向下执行。

async function fetchData() {
  const data1 = await fetch('file1');
  const data2 = await fetch('file2');
}
  • await 接收一个 Promise 对象,或者原始类型的值
  • 函数的返回值是 Promise ,因此可以再通过 then 函数,附加其它操作。
  • 函数的返回 Promise,需等到内部的所有 await 返回,或遇到 return
  • Generator 函数的语法糖,但是自带执行器,省去了 Generator 调用 next 的过程。

ES6 class

类属性的实例化写在 constructor 构造函数中,方法写在类体内,不需要 function 关键字修饰。当前 ES6 不支持私有方法和私有属性。变通的方法是,将函数与类声明在同一文件中,仅供类使用。

class Bar {
  constructor(props) {
  }
  method() {
  }
}

ES6的类相当 ES5 构造函数方法创建对象的语法糖。

Bar === Bar.prototype.constructor // true
typeof Bar // function

静态方法

使用关键字static修饰的方法为类方法,可通过类调用,可被子类继承。

class Bar {
  static foo() {
     console.log('in foo');
  }
}
Bar.foo();
// in foo

类的继承

ES6 采用关键字 extends 继承父类,子类的如果声明了构造函数(没有声明会被默认添加,任何子类都有 constructor 方法属性)中必须调用 super(),否则新建实例时会报错。

class Point { /* ... */ }

class ColorPoint extends Point {
  constructor() {
  }
}
let cp = new ColorPoint(); // ReferenceError

ES6 的子类没有自己的 this 对象,而是继承父类的 this 对象,然后对其进行加工。如果不调用 super 方法,子类就得不到 this 对象。ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。