迭代协议(Iteration protocols)

迭代协议(Iteration protocols)并不是 ECMAScript 2015新增项中的 内置功能 或 语法,而是协议。这些协议可以由遵守约定的任何对象来实现。

迭代协议有两种协议:可迭代协议(iterable protocol)迭代器协议(iterator protocol)

可迭代协议(iterable protocol)

可迭代协议允许JavaScript对象定义或自定义其迭代行为,例如:在一个 for..of 结构中定义什么值可以被循环(得到)。一些内置类型都是内置的可迭代类型并且有默认的迭代行为, 比如: ArrayMap,有些类型则不是, 比如Object

为了变成可迭代对象, 对象必须实现 @@iterator 方法, 意思是这个对象(或者它原型链上的某个对象)必须有一个名字是 Symbol.iterator 的属性,这个属性可通过Symbol.iterator访问到:


属性
[Symbol.iterator]返回一个无参数的函数,这个函数的返回值是一个符合迭代器协议的对象。

当一个对象需要被迭代的时候(例如:在for..of循环的开始),都将不带任何参数地调用其@@ iterator方法,循环中返回的迭代器用来获取要迭代的值。

迭代器协议(iterator protocol)

迭代器协议定义了一种标准的方法来生成一个值序列(有限值或无限值),并且当所有的值都已经被迭代后,就会有一个默认的返回值。

当对象使用以下语义实现 next() 方法时,它就是一个迭代器:

next() 方法没有参数,它的返回值是一个对象,这个对象至少包含 [done][value] 两个属性。

  • [done] 属性(boolean类型):当迭代器超过了迭代序列,返回true,此时value的值可以被省略;当迭代器能够继续产生序列中的下一个值,则值为false。
  • [value] 属性(boolean类型):迭代器返回的任何 JavaScript 值。done 为 true 时可省略。
注意:next() 方法必须要返回一个对象,该对象有两个必要的属性:donevalue 。如果返回一个非对象值,就会抛出TypeError (“iterator.next() returned a non-object value”) 的错误。

特定对象是否实现了 迭代器协议 我们或许不清楚,然而,我们自己可以轻松地创建同时满足 迭代器协议 和 可迭代协议 的对象(比如下面的例子)。这样做可以使迭代器可以被 各种用来迭代的语法 所使用。因此,很少希望在没有实现 可迭代的 情况下实现 迭代器协议。

//同时满足 迭代器协议 和 可迭代协议 的对象

var myIterator = {
	//迭代器协议
    next: function() {
        // ...
    },
    //可迭代协议
    [Symbol.iterator]: function() { return this }
};

使用 迭代协议(iteration protocols)的例子:

String 是一个内置的可迭代对象:
var someString = "hi";
console.log(someString[Symbol.iterator]);  // [Function: [Symbol.iterator]]
console.log(typeof someString[Symbol.iterator]);  // function
console.log(someString[Symbol.iterator]());  // Object [String Iterator] {}
console.log(someString[Symbol.iterator]() + '');  // [object String Iterator]
String 的默认迭代器会一个接一个返回该字符串的字符:
var iterator = someString[Symbol.iterator]();
iterator + "";                               // "[object String Iterator]"
 
iterator.next();                             // { value: "h", done: false }
iterator.next();                             // { value: "i", done: false }
iterator.next();                             // { value: undefined, done: true }
一些内置的语法结构,比如 spread operator (展开语法:[…val]),内部也使用了迭代协议:
console.log([...someString])  // ["h", "i"]

我们可以通过自己的 @@iterator 方法重新定义迭代行为:

var someString = new String("hi");          // need to construct a String object explicitly to avoid auto-boxing

someString[Symbol.iterator] = function() {
  return { // this is the iterator object, returning a single element, the string "bye"
    next: function() {
      if (this._first) {
        this._first = false;
        return { value: "bye", done: false };
      } else {
        return { done: true };
      }
    },
    _first: true
  };
};
console.log([...someString]);  // ["bye"]
console.log(someString + '');  // "hi"

var iterator = someString[Symbol.iterator]();
console.log(iterator.next());  // { value: 'bye', done: false }
console.log(iterator.next());  // { done: true }
console.log(iterator.next());  //{ done: true }

如果内置语法结构实现了迭代协议(Iteration protocols) ,但我们又重新用 迭代协议(Iteration protocols) 定义 了@@iterator 方法,此时内置语法结构中的迭代方式就会被改变。

可迭代对象例子

  • 内置可迭代对象
    String, Array, TypedArray, MapSet 是所有内置可迭代对象, 因为它们的原型对象都实现了 @@iterator 方法。

  • 自定义可迭代对象
    我们自己可以实现一个可迭代对象,就像这样:

var myIterator = {};
myIterator[Symbol.iterator] = function *(){
    yield 'happy';
    yield 'chen';
    yield 666;
}
console.log([...myIterator]);  // [ 'happy', 'chen', 666 ]

内置API接受可迭代性

有许多接受迭代的API,例如: Map([iterable])WeakMap([iterable])Set([iterable])WeakSet([iterable])Promise.all(iterable)Promise.race(iterable)Array.from()

有些语法也可迭代对象

有些语句和表达式也可以迭代,例如 for-of 循环、扩展语法、yield* 语句 和 析构赋值:

for (const item of ['菠萝头','可达鸭','吉尼龟']) {
    console.log(item);
}
// 菠萝头
// 可达鸭
// 吉尼龟
console.log([...'happychen']);  // [ 'h', 'a', 'p', 'p', 'y', 'c', 'h', 'e', 'n' ]

function* gen(){
    yield* ['菠萝头','可达鸭','吉尼龟'];
}
console.log(gen().next());   //{ value: '菠萝头', done: false }

格式化不好的迭代器

如果一个迭代器的 @@iterator 方法没有返回迭代器对象,那么它是格式化不好的迭代器。使用它可能会导致运行时异常或古怪的行为:

var nonWellFormedIterable = {}
nonWellFormedIterable[Symbol.iterator] = () => 1
[...nonWellFormedIterable] // TypeError: [] is not a function
forEach和iteration迭代是两个在编程中常用的概念。它们都用于遍历数据集合,并对其中的每个元素执行特定的操作。 1. forEach:forEach是一种数组方法,用于遍历数组中的每个元素并对其执行指定的操作。它接受一个回调函数作为参数,该回调函数会在数组的每个元素上执行一次。这个回调函数通常有三个参数:当前元素、当前索引和整个数组。forEach方法会按照数组的顺序依次遍历每个元素,但无法中途跳出循环。 示例代码: ``` const array = [1, 2, 3, 4, 5]; array.forEach((element, index) => { console.log(`Element at index ${index} is: ${element}`); }); ``` 输出结果: ``` Element at index 0 is: 1 Element at index 1 is: 2 Element at index 2 is: 3 Element at index 3 is: 4 Element at index 4 is: 5 ``` 2. 迭代iteration):迭代是一种通用的编程概念,用于遍历数据集合中的每个元素,不仅限于数组。迭代可以使用各种循环结构(如for循环、while循环)来实现。在每次迭代中,可以执行特定的操作,并根据需要跳出迭代。 示例代码: ``` const array = [1, 2, 3, 4, 5]; for (let i = 0; i < array.length; i++) { const element = array[i]; console.log(`Element at index ${i} is: ${element}`); } ``` 输出结果与forEach方法相同: ``` Element at index 0 is: 1 Element at index 1 is: 2 Element at index 2 is: 3 Element at index 3 is: 4 Element at index 4 is: 5 ``` 需要注意的是,迭代不仅适用于数组,还可以用于其他数据结构,如对象中的属性、链表中的节点等。在每种情况下,迭代的实现方式可能会有所不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值