-
done
通知消费者迭代器是否已经被使用,false
表示仍有值需要生成,true
表示迭代器已经结束。 -
value
可以是任何 JS 值,它是向消费者展示的值。
当done
为true
时,可以省略value
。
迭代器和可以可迭代对象可以用下面这张图来表示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qu7BEdCY-1606263454066)(/img/bVbOVew)]
基础知识介绍完了,接着,我们来配合一些事例来加深我们的映像。
范围迭代器
我们先从一个非常基本的迭代器开始,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());
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-auJn06E3-1606263454068)(/img/bVbOViQ)]
可迭代范围迭代器
在本文的前面,我已经提到 JS 中的某些语句需要一个可迭代的对象。 因此,我们前面的示例在与for ... of
循环一起使用时将不起作用。
但是创建符合迭代器
和可迭代协议
的对象非常容易。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SUzWxihn-1606263454070)(/img/bVbOVxd)]
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 将尝试消费迭代器,由于迭代器是无限的,因此它将永远不会结束。 所以你的应用程序将崩溃,因为内存已被耗尽 😱
同样,for ... of
循环也是一样的情况,所以要确保能退出循环:
function createEvenNumbersIterator () {
let value = 0
return {
[Symbol.iterator] () {
return this
},
next () {
value += 2
return { value, done: false}
}
}
}
const it = createEvenNumbersIterator()
const [a, b, c] = it
console.log({a, b, c})
const [x, y, z] = it
console.log({ x, y, z })
for (const even of it) {
console.log(even)
if (even > 20) {
break
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ziQZUuHt-1606263454074)(/img/bVbOVz3)]
关闭迭代器
前面我们提到过,迭代器可以有选择地使用return()
方法。 当迭代器直到最后都没有迭代时使用此方法,并让迭代器进行清理。
for ... of
循环可以通过以下方式更早地终止迭代:
-
break
-
continue
-
throw
-
return
function createCloseableIterator () {
let idx = 0
const data = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’]
function cleanup() {
console.log(‘Performing cleanup’)
}
return {
Symbol.iterator { return this },
next () {
if (idx <= data.length - 1) {
return { value: data[idx++], done: false }
} else {
cleanup()
return { done: true }
}
},
return () {
cleanup()
return { done: true }
}
}
}
const it = createCloseableIterator()
for (const value of it) {
console.log(value)
if (value === ‘c’) {
break
}
}
console.log(‘\n----------\n’)
const _it = createCloseableIterator();
for (const value of _it) {
console.log(value);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WitbqqEm-1606263454076)(/img/bVbOVDp)]
-
如果知道迭代器已经结束,则手动调用
cleanup()
函数。 -
如果突然完成,则
return()
起作用并为我们进行清理。
如果你已经做到了这一点,我们来看看一些额外的内容。
组合器
组合器是将现有可迭代对象组合在一起以创建新可迭代对象的函数。
因此,我们能够创建许多实用函数。那map
或者filter
呢?看看下面的代码,花一分钟时间来理解它。
function createEvenNumbersIterator() {
let value = 0;
return {
return this;
},
next() {
value += 2;
return { value, done: false };
}
}
}
function map(fn, iterable) {
const iter = iterableSymbol.iterator;
return {
return this;
},
next() {
const n = iter.next();
if (!n.done) {
return { value: fn(n.value), done: false };
} else {
return { done: true };
}
}
}
}
function filter(fn, iterable) {
const iter = iterableSymbol.iterator;
return {
return this;
},
next() {
const n = iter.next();
if (!n.done) {
if (fn(n.value)) {
return { value: n.value, done: false };
} else {
return this.next();
}
} else {
return { done: true };
}
}
}
}
function take(n, iterable) {
const iter = iterableSymbol.iterator;
前端资料汇总
我一直觉得技术面试不是考试,考前背背题,发给你一张考卷,答完交卷等通知。
首先,技术面试是一个 认识自己 的过程,知道自己和外面世界的差距。
更重要的是,技术面试是一个双向了解的过程,要让对方发现你的闪光点,同时也要 试图去找到对方的闪光点,因为他以后可能就是你的同事或者领导,所以,面试官问你有什么问题的时候,不要说没有了,要去试图了解他的工作内容、了解这个团队的氛围。
找工作无非就是看三点:和什么人、做什么事、给多少钱,要给这三者在自己的心里划分一个比例。
最后,祝愿大家在这并不友好的环境下都能找到自己心仪的归宿。