TOC
ECMAScript 6 简介
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
Iterator
Iterator(遍历器)的概念
-
基本用法: 遍历器(
Iterator
)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator
接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。 -
作用:
- 为各种数据结构,提供一个统一的、简便的访问接口
- 使得数据结构的成员能够按某种次序排列
- ES6 创造了一种新的遍历命令
for...of
循环,Iterator
接口主要供for...of
消费。
-
遍历过程:
- 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
- 调用指针对象的
next
方法,可以将指针指向数据结构的下一个成员。返回一个包含value
和done
两个属性的对象 。其中,value
属性是当前成员的值,done
属性是一个布尔值,表示遍历是否结束。 - 不断调用指针对象的
next
方法,直到它指向数据结构的结束位置。
var it = makeIterator(['a', 'b']); it.next() // { value: "a", done: false } it.next() // { value: "b", done: false } it.next() // { value: undefined, done: true } function makeIterator(array) { var nextIndex = 0; return { next: function() { return nextIndex < array.length ? {value: array[nextIndex++], done: false} : {value: undefined, done: true}; } }; } ======================== interface Iterable { [Symbol.iterator]() : Iterator, } interface Iterator { next(value?: any) : IterationResult, } interface IterationResult { value: any, done: boolean, }
默认 Iterator 接口
-
基本用法:
Iterator
接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即for...of
循环。当使用for…of循环遍历某种数据结构时,该循环会自动去寻找Iterator
接口。ES6 规定,默认的
Iterator
接口部署在数据结构的Symbol.iterator
属性,或者说,一个数据结构只要具有Symbol.iterator
属性,就可以认为是可遍历的
(iterable
)。Symbol.iterator
属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。至于属性名Symbol.iterator
,它是一个表达式,返回Symbol
对象的iterator
属性,这是一个预定义好的、类型为Symbol
的特殊值,所以要放在方括号内。const obj = { [Symbol.iterator] : function () { return { next: function () { return { value: 1, done: true }; } }; } };
-
原生具备
Iterator
接口的数据结构:- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象
for…of 循环
- 基本用法:
for...in
:遍历数组的键名forEach
:break
或return
命令无法中途跳出循环for...of
: 提供了遍历所有数据结构的统一操作接口
Generator
Generator的概念
- 基本用法:
- 语法上:
Generator
函数是一个状态机,封装了多个内部状态。执行Generator
函数会返回一个遍历器对象。 - 形式上:
Generator
函数是一个普通函数,但是有两个特征:function
关键字与函数名之间有一个星号(*
)- 函数体内部使用
yield
表达式,定义不同的内部状态(yield
在英语里的意思就是“产出”)
function* helloWorldGenerator() { yield 'hello'; yield 'world'; return 'ending'; } var hw = helloWorldGenerator();
- 语法上:
yield表达式
-
基本用法: 由于
Generator
函数返回的遍历器对象,只有调用next
方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield
表达式就是暂停标志,yield
表达式只能用在Generator
函数里面。 -
遍历器对象的
next
方法的运行逻辑:- 遇到
yield
表达式,就暂停执行后面的操作,并将紧跟在yield
后面的那个表达式的值,作为返回的对象的value
属性值。(yield
表达式本身没有返回值,或者说总是返回undefined
) - 下一次调用
next
方法时,再继续往下执行,直到遇到下一个yield
表达式。 - 如果没有再遇到新的
yield
表达式,就一直运行到函数结束,直到return
语句为止,并将return
语句后面的表达式的值,作为返回的对象的value
属性值。 - 如果该函数没有
return
语句,则返回的对象的value
属性值为undefined
。
function* helloWorldGenerator() { yield 'hello'; yield 'world'; return 'ending'; } var hw = helloWorldGenerator();
- 遇到
next 方法的参数
- 基本用法:
yield
表达式本身没有返回值,或者说总是返回undefined
。next
方法可以带一个参数,该参数就会被当作上一个yield
表达式的返回值。function* helloWorldGenerator() { yield 'hello'; yield 'world'; return 'ending'; } var hw = helloWorldGenerator();
Generator.prototype.throw()
- 基本用法:
Generator
函数返回的遍历器对象,都有一个throw
方法,可以在函数体外抛出错误,然后在Generator
函数体内捕获。var g = function* () { try { yield; } catch (e) { console.log('内部捕获', e); } }; var i = g(); i.next(); try { i.throw('a'); i.throw('b'); //Generator 函数内部的catch语句已经执行过了,不会再捕捉到这个错误了 } catch (e) { console.log('外部捕获', e); } // 内部捕获 a // 外部捕获 b //throw方法被捕获以后,会附带执行下一条yield表达式 var gen = function* gen(){ try { yield console.log('a'); } catch (e) { // ... } yield console.log('b'); yield console.log('c'); } var g = gen(); g.next() // a g.throw() // b g.next() // c
Generator.prototype.return()
- 基本用法:
Generator
函数返回的遍历器对象,还有一个return
方法,可以返回给定的值,并且终结遍历Generator
函数。function* gen() { yield 1; yield 2; yield 3; } var g = gen(); g.next() // { value: 1, done: false } g.return('foo') // { value: "foo", done: true } g.next() // { value: undefined, done: true }
next()、throw()、return() 的共同点
- 基本用法:
next()
、throw()
、return()
这三个方法本质上是同一件事,它们的作用都是让Generator
函数恢复执行,并且使用不同的语句替换``yield
表达式。
yield* 表达式
- 基本用法:
ES6 提供了
yield*
表达式,用来在一个Generator
函数里面执行另一个Generator
函数。function* foo() { yield 'a'; yield 'b'; } function* bar() { yield 'x'; yield* foo(); yield 'y'; } // 等同于 function* bar() { yield 'x'; yield 'a'; yield 'b'; yield 'y'; }
作为对象属性的 Generator 函数
let obj = {
* myGeneratorMethod() {
···
}
};
等同于
let obj = {
myGeneratorMethod: function* () {
// ···
}
};
Generator 函数的this
- 基本用法:
Generator
函数总是返回一个遍历器,ES6 规定这个遍历器是Generator
函数的实例,也继承了Generator
函数的prototype
对象上的方法。Generator
函数也不能跟new
命令一起用,会报错。function* g() {} g.prototype.hello = function () { return 'hi!'; }; let obj = g(); obj instanceof g // true obj.hello() // 'hi!'
「下次一定」
下次一定
使用微信扫描二维码完成支付