JavaScript 中的可迭代对象与迭代器是啥
本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。Lazy evaluation
Lazy evaluation
常被译为“延迟计算”或“惰性计算”,指的是仅仅在真正需要执行的时候才计算表达式的值。
与惰性求值
相反的是及早求值(eager evaluation)
及早求值,也被称为贪婪求值
(greedy evaluation)或严格求值,是多数传统编程语言的求值策略。
充分利用惰性求值
的特性带来的好处主要体现在以下两个方面:
避免不必要的计算,带来性能上的提升。节省空间,使得无限循环的数据结构成为可能。迭代器
ES6 中的迭代器使惰性求值和创建用户定义的数据序列成为可能。迭代是一种遍历数据的机制。 迭代器是用于遍历数据结构元素(称为Iterable
)的指针,用于产生值序列的指针。
迭代器是一个可以被迭代的对象。它抽象了数据容器,使其行为类似于可迭代对象。
迭代器在实例化时不计算每个项目的值,仅在请求时才生成下一个值。 这非常有用,特别是对于大型数据集或无限个元素的序列。
可迭代对象可迭代对象是希望其元素可被公众访问的数据结构。JS 中的很多对象都是可迭代的,它们可能不是很好的察觉,但是如果仔细检查,就会发现迭代的特征:
new Map([iterable])new WeakMap([iterable])new Set([iterable])new WeakSet([iterable])Promise.all([iterable])Promise.race([iterable])Array.from([iterable])还有需要一个可迭代的对象,否则,它将抛出一个类型错误,例如:
for ... of
...
(展开操作符)const [a, b, ..] = iterable
(解构赋值)yield*
(生成器)JavaScript中已有许多内置的可迭代项:
String
,Array
,TypedArray
,Map
,Set
。
迭代器和可迭对象遵循迭代协议
。
迭代器遵循迭代器协议,可迭代遵循可迭代协议。
可迭代的协议要使对象变得可迭代,它必须实现一个通过Symbol.iterator
的迭代器方法,这个方法是迭代器的工厂。
使用 TypeScript,可迭代协议如下所示:
interface Iterable {
[Symbol.iterator]() : Iterator;
}
Symbol.iterator]()
是无参数函数。 在可迭代对象上调用它,这意味着我们可以通过this
来访问可迭代对象,它可以是常规函数或生成器函数。
迭代器协议定义了产生值序列的标准方法。
为了使对象成为迭代器,它必须实现next()
方法。 迭代器可以实现return()
方法,我们将在本文后面讨论这个问题。
使用 TypeScript,迭代器协议如下所示:
interface Iterator {
next() : IteratorResult;
return?(value?: any): IteratorResult;
}
IteratorResult
的定义如下:
interface IteratorResult {
value?: any;
done: boolean;
}
done
通知消费者迭代器是否已经被使用,false
表示仍有值需要生成,true
表示迭代器已经结束。value
可以是任何 JS 值,它是向消费者展示的值。当done
为true
时,可以省略value
。
迭代器和可以可迭代对象可以用下面这张图来表示:
事例基础知识介绍完了,接着,我们来配合一些事例来加深我们的映像。
范围迭代器我们先从一个非常基本的迭代器开始,createRangeIterator
迭代器。
我们手动调用it.next()
以获得下一个IteratorResult
。 最后一次调用返回{done:true}
,这意味着迭代器现在已被使用,不再产生任何值。
function createRangeIterator(from, to) {
let i = from;
return {
next() {
if (i <= to) {
return { value: i++, done: false };
} else {
return { done: true };
}
}
}
}
const it = createRangeIterator(1, 3);
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
可迭代范围迭代器在本文的前面,我已经提到 JS 中的某些语句需要一个可迭代的对象。 因此,我们前面的示例在与for ... of
循环一起使用时将不起作用。
但是创建符合迭代器
和可迭代协议
的对象非常容易。
function createRangeIterator (from, to) {
let i = from
return {
[Symbol.iterator] () {
return this
},
next() {
if (i <= to) {
return { value: i++, done: false }
} else {
return { done: true }
}
}
}
}
const it = createRangeIterator(1, 3)
for (const i of it) {
console.log(i)
}
无限序列迭代器迭代器可以表示无限制大小的序列,因为它们仅在需要时才计算值。
注意不要在无限迭代器上使用扩展运算符(...
),JS 将尝试消费迭代器,由于迭代器是无限的,因此它将永远不会结束。 所以你的应用程序将崩溃,因为内存已被耗尽
版权声明
本文仅代表作者观点,不代表博信信息网立场。