AI 读源码之 arrify
源码作用
这个迷你的小库,是将传入的值,转化为数组。它的自我介绍是——
Convert a value to an array
源码速览
源码非常简单,只有十来行,非常迷你。
export default function arrify(value) {
if (value === null || value === undefined) {
return [];
}
if (Array.isArray(value)) {
return value;
}
if (typeof value === 'string') {
return [value];
}
if (typeof value[Symbol.iterator] === 'function') {
return [...value];
}
return [value];
}
AI 解读源码
源码前面都比较好理解,关键是 typeof value[Symbol.iterator] === 'function'
这个判断分支是什么情况呢?我请教了万能的 ChatGPT,并将它的回答翻译并整理如下:
在 arrify 函数中, if (typeof value[Symbol.iterator] === 'function') 行正在检查该值是否具有遍历器接口。
在 JavaScript 中,Symbol.iterator 符号用于创建自定义可遍历对象。 可遍历对象是一个具有遍历器的对象,它允许使用 for...of 循环或扩展运算符 (...) 对其进行循环。
它的工作原理如下:
当您在可遍历对象上使用扩展运算符 (...) 时,它将在内部调用可遍历对象的 Symbol.iterator 方法来获取指针对象。
指针对象是一个具有 next 方法的对象,该方法返回下一个值和指示遍历是否完成的 done 属性。
因此,当
typeof value[Symbol.iterator] === 'function'
计算结果为 true 时,这意味着 value 是一个可遍历对象,您可以使用扩展运算符将其转换为带有 [...value] 的数组。例如,假设 value 是一个 Set 对象:
const set = new Set([1, 2, 3]);
const array = [...set];
console.log(array); // Output: [1, 2, 3]
在这种情况下,条件 typeof value[Symbol.iterator] === 'function' 将计算为 true,并且扩展运算符将用于将 Set 转换为数组。
arrify 函数中的这种检查允许它处理不同类型的输入,并在需要时将它们转换为数组。 它有助于确保返回值始终是一个数组,无论输入类型如何。
这个回答基本符合我们对遍历器的印象。不过,尽信书不如无书,全靠 AI 就坐等失业。我们还要验证一下 AI 这个回答。
人工解读源码
首先,我查阅关于遍历器的资料,基本验证 AI 的回答正确。
遍历器相关术语有些容易混淆,这里借用阮一峰大佬的中文翻译和 TS 版本规格描述:
interface Iterable { // 遍历器接口
[Symbol.iterator]() : Iterator, // 注意该方法执行后才返回 Iterator
}
interface Iterator { // 指针对象
next(value?: any) : IterationResult,
}
interface IterationResult { // 指针对象的 next 方法返回值
value: any,
done: boolean,
}
接着就是重点,自己写一个实现了遍历器接口的对象,看 arrify 能不能很好处理。
const obj = {
data: [0, 1, 2, 3, 4, 5, 6, 7],
[Symbol.iterator]() {
let pointer = 0;
return {
next: () => {
if ((pointer) % 3 === 0) {
pointer++;
}
if (pointer < this.data.length) {
return {
value: this.data[pointer++],
done: false,
};
}
return {
done: true,
};
}
};
}
};
这个 obj 是我写的一个对象,它自己有一个 Symbol.iterator
属性,并实现了遍历器接口。为了彰显它自己的个性,每逢 3 的倍数都会跳过遍历。我们先尝尝它的 Symbol.iterator
属性方法返回的指针对象 iterator 能否正常使用。
// 手动遍历,调用指针对象的 next 方法。结果分行输出 1 2 4 5 7
const it = obj[Symbol.iterator]();
let res = it.next();
while (!res.done) {
console.log(res.value);
res = it.next();
}
// for of 遍历。结果分行输出 1 2 4 5 7
for (const v of obj) {
console.log(v);
}
// obj 不是数组,但是可以使用 Array.from 和扩展运算符转换为数组
console.log(Array.isArray(obj)); // false
console.log(Array.from(obj)); // [ 1, 2, 4, 5, 7 ]
console.log([...obj]); // [ 1, 2, 4, 5, 7 ]
运行结果符合预期,说明 obj 对象实现了遍历器接口。接着我们用 arrify 来处理一下。
console.log(arrify(obj)); // [ 1, 2, 4, 5, 7 ]
arrify 也很好地将它转化为数组了。
总结
arrify 是一个用于将值转化为数组的库。解读源码过程中,Symbol.iterator
属性的使用值得学习。对于简单的源码,AI 的解读也基本靠谱,能提升我们学习的效率。
转载自:https://juejin.cn/post/7269693193138290748