最简单的手机网站制作如何用服务器做网站
什么是迭代器?
JS 迭代器是一种遍历访问数据结构中所有成员的机制,本质是一个指针对象。
为什么要有迭代器?
- 为各种不同的数据结构提供统一的访问机制。
- 自定义数据结构的遍历:当你创建了一个自定义的数据结构时,可以实现迭代器来方便地遍历其中的元素。
- 惰性计算:迭代器可以实现惰性计算,即只有在需要时才计算下一个值,这样可以节省内存和计算资源。
- 异步迭代器,可以用于处理异步数据流。
迭代器的遍历过程
-
创建一个指针对象,指向数据结构的起始位置。
-
第一次调用指针对象的 next 方法,指针指向数据结构的第一个成员。
-
第二次调用指针对象的 next 方法,指针指向数据结构的第二个成员。
-
依此类推,不断调用指针对象的 next 方法……
-
当指针指向数据结构的结束位置,遍历结束
可迭代对象
实现了迭代器的对象(拥有返回一个具备 next 方法的 Symbol.iterator 方法),被称为可迭代对象
(如字符串、数组、Set、Map 、Object 等),可通过 for…of 语句遍历。
Symbol.iterator 是一个 Symbol 类型的值,它是 JavaScript 内置的一个特殊 Symbol,用来表示对象的迭代器方法。由于它是 Symbol 类型而非普通字符串,所以不能直接当作静态属性名来使用,而需要通过计算属性名的方式来定义或访问(即需要用 [] 包裹使用)。
可迭代对象调用其 Symbol.iterator 方法会得到一个用于遍历该对象元素的迭代器。
const arr = [1, 2];
const iterator = arr[Symbol.iterator]();console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
内置可迭代对象
JS 内置实现了迭代器的对象(具有 Symbol.iterator 属性)有:
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象
自定义可迭代对象
// 创建一个可迭代对象
const myIteratorObject = {data: [1, 2, 3, 4, 5],[Symbol.iterator]() {let index = 0;return {next: () => {if (index < this.data.length) {return { value: this.data[index++], done: false };} else {return { done: true };}}};}
};// 使用 for...of 循环遍历自定义的可迭代对象
for (const value of myIteratorObject) {console.log(value);
}
触发迭代器的场景
-
for…of 循环
-
对数组和 Set 结构进行解构赋值
-
扩展运算符(…)
-
yield*
可迭代对象在 yield* 后时,会触发迭代器let generator = function* () {yield 1;yield* [2,3,4];yield 5; };var iterator = generator();iterator.next() // { value: 1, done: false } iterator.next() // { value: 2, done: false } iterator.next() // { value: 3, done: false } iterator.next() // { value: 4, done: false } iterator.next() // { value: 5, done: false } iterator.next() // { value: undefined, done: true }
-
Array.from()
-
Map(), Set(), WeakMap(), WeakSet()(比如new Map([[‘a’,1],[‘b’,2]]))
-
Promise.all()
-
Promise.race()
可迭代对象转数组
只要某个数据结构实现了迭代器,就可以对它使用扩展运算符,将其转为数组。
let arr = [...iterable];
return()方法
可迭代对象除了具有next()方法,还可以具有return()方法,但可以选择性实现。
如果for…of循环提前退出(通常是因为出错,或者有break语句),就会调用return()方法。
如果一个对象在完成遍历前,需要清理或释放资源,就可以通过return()方法。
return()方法必须返回一个对象
function readLinesSync(file) {return {[Symbol.iterator]() {return {next() {return { done: false };},return() {file.close();return { done: true };}};},};
}
下面的两种情况,都会触发执行return()方法。
// 情况一
for (let line of readLinesSync(fileName)) {console.log(line);break;
}// 情况二
for (let line of readLinesSync(fileName)) {console.log(line);throw new Error();
}
同步迭代器
迭代器有 next 方法,返回一个包含 value 和 done 两个属性的对象。
- value 属性:当前迭代位置的值,可为任意类型( TS 中为 any) 。(即当前指针指向的数据结构的成员),当值为 undefined 时可省略。
- done 属性:是否已迭代结束,布尔值,true 表明迭代结束,false 则意味着还有成员可供迭代,当值为 false 时可省略。
// 自定义迭代器
const myIterator = {// 需要遍历的成员data:[1,2,3],// 因第一个元素下标为 0 ,起始位置从 -1 开始index: -1,// 迭代器的核心方法 next next() {this.index++;// next 方法返回一个包含 value 和 done 两个属性的对象return {value: this.data[this.index], done: this.index === this.data.length };},// 为了后续可用 for of 语句遍历,详见下文中可迭代对象的解析[Symbol.iterator]() {return this;},
};for (const item of myIterator) {console.log(item); //1 2 3
}
异步迭代器
异步迭代器和同步迭代器相似,主要用于处理异步数据。
其 next 方法返回一个 Promise,该 Promise 会解析为一个包含 value 和 done 属性的对象。
// 定义异步迭代器
const asyncNumberIterator = {current: 0,max: 3,async next() {// 模拟异步操作await new Promise(resolve => setTimeout(resolve, 1000));if (this.current <= this.max) {const value = this.current++;return { value, done: false };}return { done: true };},[Symbol.asyncIterator]() {return this;}
};// 使用异步迭代器,需用 for await of
(async () => {for await (const num of asyncNumberIterator) {console.log(num);}
})();
TS 给迭代器标注类型
// 迭代器接口
interface Iterable {[Symbol.iterator]() : Iterator,
}// 迭代器指针
interface Iterator {next(value?: any) : IterationResult,
}// next 的返回值
interface IterationResult {value: any,done: boolean,
}
使用生成器实现迭代器
用 yield 命令给出每一步的返回值即可。
let obj = {* [Symbol.iterator]() {yield 'hello';yield 'world';}
};for (let x of obj) {console.log(x);
}
// "hello"
// "world"
【实战】迭代器实现“链表”结构
function Obj(value) {this.value = value;this.next = null;
}Obj.prototype[Symbol.iterator] = function() {var iterator = { next: next };var current = this;function next() {if (current) {var value = current.value;current = current.next;return { done: false, value: value };}return { done: true };}return iterator;
}var one = new Obj(1);
var two = new Obj(2);
var three = new Obj(3);one.next = two;
two.next = three;for (var i of one){console.log(i); // 1, 2, 3
}
【实战】类似数组的对象实现迭代器
存在数值键名和length属性的对象为类似数组的对象。
将其 Symbol.iterator方法直接引用数组的 Iterator 接口可快捷实现迭代器
let iterable = {0: 'a',1: 'b',2: 'c',length: 3,[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {console.log(item); // 'a', 'b', 'c'
}