浏览器巴哥?深究一次浏览器内置可迭代对象的发现通过一次开发粘贴功能,发现了浏览器的快照和垃圾回收机制的相辅相成,进一步了
1.故事背景
客户提了一个想要粘贴上传图片的需求,接到这个需求的时候,一想这不so easy?但是实现过程中,着实发现了自己的知识盲区,也让自己对基础复习了一把,主要分为以下几点:
1.可迭代对象和迭代器
2.浏览器快照和垃圾回收机制
2.粘贴事件
这个粘贴功能的实现其实是非常简易的,代码如下(只贴关键部分):
<el-upload @paste.native="handlePaste" ></el-upload>
handlePaste(event) {
console.log(event,'event')
const clipboardItems = event.clipboardData.items;
for (let item of clipboardItems) {
if (item.type.includes('image')) {
const file = item.getAsFile();
let formData = new FormData();
formData.append("file", file);
uploadFile(formData)
break;
}
}
},
按照这段代码的逻辑,先获取事件对象中粘贴板对象的clipboardData中的items,然后遍历了items,所以我打印了event事件对象,去观察这个数据结构
但是无论我如何粘贴,我发现这个items的length都是0,此时我就觉得这个items是空的,也就是说我们没有获得粘贴的数据,然后去百度了半天,还没发现蹊跷。后来我做了进一步打印直接打印这个items,结果如下
一阵错愕!这是浏览器的bug吧?这是什么属性,length表面上看着是0,展开了又是1.这到底是为什么啊,后来把这个问题分享给了一个掘友,她发现是console.log属于浏览器快照以及垃圾回收机制导致的,所以说有时console.log也是不靠谱的,有感兴趣的可以看看下面这位掘友姐姐的文章
而我对这个DataTransferItemList更感兴趣,了解到它是一种类数组,可迭代对象。远古的知识在脑海中浮现但是记得不是特别清楚,于是翻开了红宝书。
2.可迭代对象与迭代器
2.1.可迭代对象的实现
在JavaScript中,迭代器(Iterator)是一种对象,它能够遍历并选择暴露(yield)它的元素。迭代器模式是一种行为设计模式,它提供了一种方法来顺序访问聚合对象中的各个元素,而又不需要暴露该对象的内部表示。而我只想知道我怎么样可以实现一个可迭代对象呢?为了实现可迭代,对象必须实现 [Symbol.iterator]()
方法,这意味着这个对象(或其原型链中的任意一个对象)必须具有一个键值为 Symbol.iterator
的属性。
const iteratorObj= {
arr: ['我', '妻', '善','逸'],
[Symbol.iterator]:function() {
let index = 0;
return {
next: () => {
if (index < this.arr.length) {
return { value: this.arr[index++], done: false };
} else {
return { done: true };
}
}
};
}
};
2.2.自定义奇奇怪怪的迭代器
众所周知迭代器获得下一个元素的方式就是不断调用next(),这让我联想到了链表,大胆猜想,因为数据结构是整齐的所以比链表应该要高效很多,和链表相同额是next可看作指针,所以我们来写自定义的迭代器,只需要接着首元素的next指针来继续写我们需要的遍历逻辑就可以了,所以尝试写几个可能会用的,其实也不会用
反向迭代数组
function* reverseIterator(iterable) {
const array = Array.from(iterable);
for (let i = array.length - 1; i >= 0; i--) {
yield array[i];
}
}
过滤元素
//过滤元素
filterIterator = function (arr) {
let iterator = arr[Symbol.iterator]()
return arrIterator = {
[Symbol.iterator]: function () {
return {
next() {
const { value, done } = iterator.next();
//加过滤条件就可以
if (value === 3) {
return iterator.next();
}
return { value, done };
}
}
}
}
}
3.迭代器的场景
迭代器还在许多场景中应用,例如:
- 当你需要遍历复杂的数据结构,如树或图时。
- 当你想要创建一个可以懒加载数据的系统时(例如,只在需要时从服务器加载数据)。
- 当你需要实现自定义的遍历逻辑时,如逆序遍历数组或跳过某些元素。
tip:作为程序员如何知道可迭代对象的能多次迭代还是只能迭代一次?MDN中有说到,就是当它第一次调用Symbol.iterator去做迭代时,判断迭代之后的对象是不是它自己,如果是,它只能迭代一次,如果不是它就可以多次迭代
console.log(it[Symbol.iterator]() === it); // true
转载自:https://juejin.cn/post/7414321375550750746