Built-in iterable objects
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:
-
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" }
-
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