✍️述-iterator

Iterable Protocol

The iterable protocol allows JavaScript objects to define or customize their iteration behavior, such as what values are looped over in a for..of construct. Some built-in types are built-in iterables with a default iteration behavior, such as Array or Map, while other types (such as Object) are not.

暂译为

Iterable Protocol允许javascript对象自定义自身的遍历机制,例如目前es6已有的for..of方法,包括内建数据类型自身就有其默认的遍历机制,例如Array, Map


之所以会探究这个问题,是因为面试过程中有这样一个问题,🔨误打误撞进入新世界!

es6的语法-spread operator操作符是否使用过,对于可以使用该操作符的对象,有没有什么要求?

一句话总结,只有实现Iterable Protocol的对象才可以被展开

那么,从哪儿可以窥探到Iterable Protocol呢?

📖[Symbol.iterator]

Iterable Protocol的入口就是这些可操作对象的一个keySymble.iterator,由MDN,这种写法是规定好的,是一个常量。

In order to be iterable, an object must implement the @@iterator method, meaning that the object (or one of the objects up its prototype chain) must have a property with a @@iterator key which is available via constant Symbol.iterator:

所以只要重写了这个方法@@iterator就可以自定义一种遍历机制,进而可以影响到spread操作符的效果

📖iteration behavior

下面示例简单展示如何重写遍历方法自定义遍历机制

为何会出现yield,是因为需要使用generators来实现这个方法,通过next来完成


var myIterable = {};

myIterable[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
};

[...myIterable]; // [1, 2, 3]

1
2
3
4
5
6
7
8
9
10
11

下面展示一种斐波那契数列的实现方法:

let memo = [0, 1]

const fibo = (n) => memo[n] !== undefined ? memo[n] : (memo[n] = fibo(n - 1) + fibo(n - 2))

function* gen(n = 0) {
    fibo(n)
    yield* memo.slice(0, n)
}

const [...g] = gen(50)


/** 认识 iterable protocol */
// g[Symbol.iterator] = function* () {
//     yield 'a'
//     yield 'b'
//     yield 'c'
// }


// const i = g[Symbol.iterator]()
// g.forEach(o => console.info(i.next()))
/** 认识 end */

console.info(g, g[g.length - 1]) // g[g.length - 1] 为所求位置的数字
const end = +new Date()
console.info(end - start)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

参考:MDN-Iterable Protocol