es6迭代协议

迭代协议

迭代协议分为两个协议:可迭代协议迭代器协议

可迭代协议

可迭代协议允许 JavaScript 对象定义或定制它们的迭代行为。如果一个对象(或它原型链上的对象)实现了**[Symbol.iterator]方法,称该对象满足可迭代协议,也称该对象为可迭代对象**。

[Symbol.iterator]方法返回一个无参函数,该函数返回值为一个满足迭代器协议的对象,即迭代器对象

一个可迭代对象是如何被迭代的?

当一个对象需要被迭代的时候(比如被置入一个 for...of 循环时),首先,会不带参数调用它的 [Symbol.iterator] 方法,然后使用此方法返回的迭代器获得要迭代的值。

迭代器协议

迭代器协议定义了产生一系列值(无论是有限个还是无限个)的标准方式。一个对象必须实现了具有如下特征的next()方法,才能称其为迭代器对象

1、next() 方法是一个无参函数,返回值为一个特殊对象。

2、返回的特殊对象拥有两个属性:done(布尔值),value。

3、done的取值:如果迭代器可以产生序列中的下一个值,则为 false;如果迭代器已将序列迭代完毕,则为 true,这种情况下,value 是可选的,如果它依然存在,即为迭代结束之后的默认返回值(undefined)。

4、value的取值:任何 JavaScript 值。

5、next() 方法必须返回一个对象,该对象应当有两个属性: donevalue,如果返回了一个非对象值,则会抛出异常。

创造一个同时满足迭代器协议和可迭代协议的对象:

var myIterator = {
    next: function() {
        // ...
    },
    [Symbol.iterator]: function() { return this }
}

可迭代对象

内置可迭代对象有:StringArrayTypedArrayMapSet,它们的原型对象都实现了 [Symbol.iterator] 方法。

自定义可迭代对象:

var myIterable = {};
myIterable[Symbol.iterator] = function* () {// 生成器函数
    yield 1;
    yield 2;
    yield 3;
};
[...myIterable]; // [1, 2, 3]

接收可迭代对象的内置API:

  • new Map([iterable])

  • new WeakMap([iterable])

  • new Set([iterable])

  • new WeakSet([iterable])

  • Promise.all(iterable)

  • Promise.race(iterable)

  • Array.from(iterable)

    例如:

new Map([[1, 'a'], [2, 'b'], [3, 'c']]).get(2); // "b"

let myObj = {};

new WeakMap([
    [{}, 'a'],
    [myObj, 'b'],
    [{}, 'c']
]).get(myObj);             // "b"

new Set([1, 2, 3]).has(3); // true
new Set('123').has('2');   // true

new WeakSet(function* () {
    yield {};
    yield myObj;
    yield {};
}()).has(myObj);           // true

需要可迭代对象的语法:

一些语句和表达式需要可迭代对象,比如 for...of 循环、展开语法、yield*,和解构赋值:

for(let value of ["a", "b", "c"]){
    console.log(value);
}
// "a"
// "b"
// "c"

[..."abc"]; // ["a", "b", "c"]

function* gen() {
  yield* ["a", "b", "c"];
}

gen().next(); // { value: "a", done: false }

[a, b, c] = new Set(["a", "b", "c"]);
a // "a"

格式不佳的可迭代对象:如果一个可迭代对象的 [Symbol.iterator] 方法不能返回迭代器对象,那么可以认为它是一个格式不佳的(Non-well-formed)可迭代对象 。

使用这样的可迭代对象很可能会导致如下的运行时(runtime)异常,或者不可预料的表现:

var nonWellFormedIterable = {}
nonWellFormedIterable[Symbol.iterator] = () => 1
[...nonWellFormedIterable] // TypeError: [] is not a function

迭代器示例

返回简单迭代器的函数:

function makeIterator(array) {
    let nextIndex = 0;
    return {
       next: function () {
           if(nextIndex < array.length) {
               return {
                   value: array[nextIndex++],
               	   done: false
               }
           }
           else {
               return {
                   done: true
               }
           }
       }
    }
}

let it = makeIterator(['哟', '呀']);

console.log(it.next().value); // '哟'
console.log(it.next().value); // '呀'
console.log(it.next().done);  // true

返回无穷迭代器的函数:

function idMaker() {
    let index = 0;
    return {
       next: function() {
           return {
               value: index++,
               done: false
           };
       }
    };
}

let it = idMaker();

console.log(it.next().value); // '0'
console.log(it.next().value); // '1'
console.log(it.next().value); // '2'
// ...

使用生成器:

// 简单生成器
function* makeSimpleGenerator(array) {
    let nextIndex = 0;
    while(nextIndex < array.length) {
        yield array[nextIndex++];
    }
}
let gen = makeSimpleGenerator(['哟', '呀']);
console.log(gen.next().value); // '哟'
console.log(gen.next().value); // '呀'
console.log(gen.next().done);  // true

// 无穷生成器
function* idMaker() {
    let index = 0;
    while (true) {
        yield index++;
    }
}
let gen = idMaker();
console.log(gen.next().value); // '0'
console.log(gen.next().value); // '1'
console.log(gen.next().value); // '2'
// ...

es6类中的迭代器(自定义可迭代对象):

class SimpleClass {
  constructor(data) {
    this.data = data
  }
  [Symbol.iterator]() {
    let index = 0;
    return {
      next: () => {
        if (index < this.data.length) {
          return {value: this.data[index++], done: false}
        } else {
          return {done: true}
        }
      }
    }
  }
}

const simple = new SimpleClass([1,2,3,4,5]);
for (const val of simple) {
  console.log(val)   //1 2 3 4 5
}

生成器对象到底是一个迭代器对象,还是一个可迭代对象?

结论是:生成器对象既是迭代器,也是可迭代对象。

let aGeneratorObject = function* (){
    yield 1;
    yield 2;
    yield 3;
}();

typeof aGeneratorObject.next;
// 返回"function", 因为有一个next方法,所以这是一个迭代器

typeof aGeneratorObject[Symbol.iterator];
// 返回"function", 因为有一个@@iterator方法,所以这是一个可迭代对象

aGeneratorObject[Symbol.iterator]() === aGeneratorObject;
// 返回true, 因为@@iterator方法返回自身(即迭代器),所以这是一个格式良好的可迭代对象

[...aGeneratorObject];
// 返回[1, 2, 3]

console.log(Symbol.iterator in aGeneratorObject)
// 返回true, 因为@@iterator方法是aGeneratorObject的一个属性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@前端攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值