阿里云主机折上折
  • 微信号
Current Site:Index > Basic concepts of the iteration protocol

Basic concepts of the iteration protocol

Author:Chuan Chen 阅读数:63720人阅读 分类: JavaScript

Core Concepts of Iteration Protocols

ECMAScript 6 introduced the iteration protocols, providing a unified mechanism for traversing data structures. The iteration protocols are not new built-in objects but a set of rules that any object can follow to implement iterable behavior. The protocols consist of two core parts: the iterable protocol and the iterator protocol.

Iterable Protocol

The iterable protocol requires an object to implement the @@iterator method, accessible via the Symbol.iterator key. When an object needs to be iterated (e.g., in a for...of loop), this method is automatically called.

const iterableObject = {
  data: [1, 2, 3],
  [Symbol.iterator]() {
    let index = 0;
    return {
      next: () => {
        if (index < this.data.length) {
          return { value: this.data[index++], done: false };
        }
        return { done: true };
      }
    };
  }
};

for (const item of iterableObject) {
  console.log(item); // Outputs 1, 2, 3 in sequence
}

Iterator Protocol

The iterator protocol defines a standard way to produce a sequence of values. An iterator is an object that implements a next() method, which returns an object with two properties:

  • value: The current value in the iteration
  • done: A boolean indicating whether the iteration is complete
function createIterator(array) {
  let nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        { value: array[nextIndex++], done: false } :
        { done: true };
    }
  };
}

const iterator = createIterator(['a', 'b']);
console.log(iterator.next()); // { value: 'a', done: false }
console.log(iterator.next()); // { value: 'b', done: false }
console.log(iterator.next()); // { done: true }

Built-in Iterables

Many built-in objects in JavaScript are iterable by default:

  • Array
  • String
  • Map
  • Set
  • arguments object
  • DOM NodeList
// String iteration
for (const char of 'hello') {
  console.log(char); // h, e, l, l, o
}

// Map iteration
const map = new Map([['a', 1], ['b', 2]]);
for (const [key, value] of map) {
  console.log(key, value); // a 1, b 2
}

Generators and Iteration Protocols

Generator functions return generator objects that are both iterable and iterators, naturally conforming to the iteration protocols:

function* generator() {
  yield 1;
  yield 2;
  yield 3;
}

const gen = generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }

// Can also be directly iterated
for (const num of generator()) {
  console.log(num); // 1, 2, 3
}

Custom Iteration Behavior

By implementing the iteration protocols, you can define iteration behavior for custom objects:

class Range {
  constructor(start, end, step = 1) {
    this.start = start;
    this.end = end;
    this.step = step;
  }

  *[Symbol.iterator]() {
    let current = this.start;
    while (current <= this.end) {
      yield current;
      current += this.step;
    }
  }
}

const range = new Range(1, 5);
for (const num of range) {
  console.log(num); // 1, 2, 3, 4, 5
}

Early Termination of Iterators

Iterators can optionally implement a return() method, which is called when iteration is terminated early (e.g., via break or an error):

const iterable = {
  [Symbol.iterator]() {
    let count = 0;
    return {
      next() {
        count++;
        return { value: count, done: count > 3 };
      },
      return() {
        console.log('Iteration terminated early');
        return { done: true };
      }
    };
  }
};

for (const item of iterable) {
  console.log(item);
  if (item === 2) break;
}
// Output:
// 1
// 2
// Iteration terminated early

Asynchronous Iteration Protocol

ES2018 introduced the asynchronous iteration protocol, similar to synchronous iteration but returning Promises:

const asyncIterable = {
  [Symbol.asyncIterator]() {
    let i = 0;
    return {
      next() {
        if (i < 3) {
          return Promise.resolve({ value: i++, done: false });
        }
        return Promise.resolve({ done: true });
      }
    };
  }
};

(async function() {
  for await (const item of asyncIterable) {
    console.log(item); // 0, 1, 2
  }
})();

Applications of Iteration Protocols

The iteration protocols are used by many JavaScript features:

  • for...of loops
  • Spread operator ...
  • Destructuring assignment
  • Array.from()
  • new Map() / new Set()
  • Promise.all() / Promise.race()
  • yield*
// Spread operator
const set = new Set([1, 2, 3]);
console.log([...set]); // [1, 2, 3]

// Destructuring assignment
const [first, second] = new Set(['a', 'b', 'c']);
console.log(first, second); // a b

// yield*
function* concatIterables(...iterables) {
  for (const iterable of iterables) {
    yield* iterable;
  }
}

const combined = concatIterables([1, 2], 'ab', new Set([3, 4]));
console.log([...combined]); // [1, 2, 'a', 'b', 3, 4]

Iterator Utility Functions

You can create various iterator utility functions to manipulate iterables:

function* map(iterable, mapper) {
  for (const item of iterable) {
    yield mapper(item);
  }
}

function* filter(iterable, predicate) {
  for (const item of iterable) {
    if (predicate(item)) {
      yield item;
    }
  }
}

function* take(iterable, n) {
  let count = 0;
  for (const item of iterable) {
    if (count++ >= n) break;
    yield item;
  }
}

const numbers = [1, 2, 3, 4, 5];
const result = take(filter(map(numbers, x => x * 2), x => x > 4), 2);
console.log([...result]); // [6, 8]

Performance Considerations with Iteration Protocols

Direct use of the iteration protocols can offer memory efficiency advantages by enabling lazy evaluation:

function* generateLargeArray() {
  for (let i = 0; i < 1000000; i++) {
    yield i;
  }
}

// Does not create an array with 1 million elements all at once
for (const num of generateLargeArray()) {
  if (num > 10) break;
  console.log(num);
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:常用内置Symbols介绍

下一篇:可迭代对象

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.