阿里云主机折上折
  • 微信号
Current Site:Index > Built-in iterable objects

Built-in iterable objects

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

ECMAScript 6 Built-in Iterable Objects

ECMAScript 6 introduced the iteration protocol, enabling objects to be iterable. Many built-in objects implement the iterable interface and can be directly used in for...of loops or other scenarios that consume iterators.

Iterability of Arrays

Arrays are the most common iterable objects. In ES6, the Symbol.iterator method is deployed on the prototype of array instances:

const arr = ['a', 'b', 'c'];
const iterator = arr[Symbol.iterator]();

console.log(iterator.next()); // { value: 'a', done: false }
console.log(iterator.next()); // { value: 'b', done: false }
console.log(iterator.next()); // { value: 'c', done: false }
console.log(iterator.next()); // { value: undefined, done: true }

Arrays iterate by returning element values in index order. Empty positions in sparse arrays return undefined:

const sparseArr = [1, , 3];
for (const item of sparseArr) {
  console.log(item); // Outputs: 1, undefined, 3 in sequence
}

Character Iteration in Strings

Strings are also iterable objects, with the iterator returning characters one by one based on Unicode code points:

const str = '你好';
for (const char of str) {
  console.log(char); // Outputs: '你', '好' in sequence
}

Unlike traditional for loops, this approach correctly handles surrogate pairs:

const emoji = '😊';
console.log(emoji.length); // 2

// Traditional methods split surrogate pairs
for (let i = 0; i < emoji.length; i++) {
  console.log(emoji[i]); // Outputs garbled characters
}

// for...of handles it correctly
for (const char of emoji) {
  console.log(char); // Correctly outputs '😊'
}

Iteration Behavior of Map and Set

Map's iterator returns key-value pairs as arrays, maintaining insertion order:

const map = new Map([
  ['key1', 'value1'],
  ['key2', 'value2']
]);

for (const [key, value] of map) {
  console.log(`${key}: ${value}`);
}
// Outputs:
// key1: value1
// key2: value2

Map also provides three separate iterator methods:

map.keys();    // Iterator for keys
map.values();  // Iterator for values
map.entries(); // Iterator for key-value pairs (default iterator)

Set's iterator returns the values in the collection, also maintaining insertion order:

const set = new Set([1, 2, 3]);
for (const value of set) {
  console.log(value); // Outputs 1, 2, 3 in sequence
}

Numeric Iteration in TypedArray

Typed arrays are also iterable objects, returning array elements in order:

const uint8Array = new Uint8Array([0x10, 0x20, 0x30]);
for (const byte of uint8Array) {
  console.log(byte.toString(16)); // Outputs '10', '20', '30' in sequence
}

Iterability of the Arguments Object

Although the arguments object is not an array, in ES6 environments it implements the iterable interface:

function iterateArgs() {
  for (const arg of arguments) {
    console.log(arg);
  }
}
iterateArgs(1, 'two', false);
// Outputs: 1, 'two', false in sequence

Iteration Support for NodeList

The DOM's NodeList object is also iterable in browsers that support ES6:

const nodeList = document.querySelectorAll('div');
for (const node of nodeList) {
  console.log(node); // Outputs each div element in sequence
}

Iterators from Generator Functions

Generator functions return generator objects, which are themselves iterable:

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

const generator = gen();
for (const num of generator) {
  console.log(num); // Outputs 1, 2, 3 in sequence
}

Destructuring Assignment with Iterables

Array destructuring actually uses the iteration protocol:

const [first, second] = new Set([1, 2]);
console.log(first, second); // 1 2

Feature Differences Among Built-in Iterables

Different built-in iterables exhibit distinct behaviors during iteration:

  1. Modifying Collections During Iteration:

    • Arrays allow modification during iteration
    const arr = [1, 2, 3];
    for (const item of arr) {
      console.log(item);
      if (item === 2) arr.push(4); // Does not affect current iteration
    }
    // Outputs 1, 2, 3
    
    • Maps and Sets throw errors if modified during iteration
    const map = new Map([[1, 'one']]);
    for (const [key] of map) {
      map.set(2, 'two'); // Throws "TypeError: map is not extensible"
    }
    
  2. Iterator Consumption: Most built-in iterables return a new iterator each time Symbol.iterator is called:

    const arr = [1, 2];
    const iter1 = arr[Symbol.iterator]();
    iter1.next();
    const iter2 = arr[Symbol.iterator]();
    console.log(iter2.next().value); // 1 (starts from the beginning)
    

    But generator objects can only be iterated once:

    function* gen() { yield 1; yield 2; }
    const g = gen();
    console.log([...g]); // [1, 2]
    console.log([...g]); // [] (already exhausted)
    

API Consumption of Iterables

Many APIs can consume iterables:

// Spread operator
const map = new Map([[1, 'one']]);
console.log([...map]); // [[1, 'one']]

// Array.from
const set = new Set([1, 2, 3]);
console.log(Array.from(set)); // [1, 2, 3]

// Promise.all
Promise.all(new Set([
  Promise.resolve(1),
  Promise.resolve(2)
])).then(console.log); // [1, 2]

Lazy Evaluation in Iterables

Built-in iterables typically implement lazy evaluation:

function* generateItems() {
  console.log('Start');
  yield 1;
  console.log('After 1');
  yield 2;
  console.log('End');
}

// Execution occurs only when needed
const iterator = generateItems();
console.log('Preparing to iterate');
const first = iterator.next(); // Now outputs "Start"
console.log('Retrieved first value');

The return Method in Iterables

Some built-in iterables' iterators implement a return method for early termination:

const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();

console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.return('early end')); // { value: 'early end', done: true }
console.log(iterator.next()); // { value: undefined, done: true }

Iterable Protocol and Array-like Objects

Array-like objects can become iterable by implementing Symbol.iterator:

const arrayLike = {
  0: 'a',
  1: 'b',
  length: 2,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
};

for (const item of arrayLike) {
  console.log(item); // Outputs 'a', 'b' in sequence
}

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

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

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 ☕.