- 本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
- 这是源码共读的第33期,链接:juejin.cn/post/710021…
一、源码阅读
简单看了这个方法的源码,他主要就是通过传递一个值,判断规则如下:
1.当为undefined 和 null这种的,返回一个空数组;
2.当为一个数组时,返回原值;
3.当为一个字符串时,将字符串放入空数组返回;
4.当为一个可迭代对象时,将可迭代对象使用展开运算符到一个数组中返回;
5.不满足以上条件的,都使用一个将值放入空数组中返回。
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];
}
二、拓展
这里面Symbol.iterator吸引了我的注意,从MDN上查到这个是给对象添加默认的迭代器。
const iterable1 = {};
iterable1[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
console.log([...iterable1]);
// Expected output: Array [1, 2, 3]
这里给iterable1添加了一个默认的迭代器,所以展开得到的属性就是1,2,3;而Symbol.iterator目前支持的就只有数组、字符串、set集合、map集合、TypeArray(类型数组)。
当看到这里那么function*这个表达式也引起我的注意,通过查询知道它是一个表达器,可以在内部定义生成器函数。
1.迭代器
简单解释为可以使用for...of来便利的对象,那么该迭代对象可以使用 ...展开运算符、结构赋值的方式。String、Array、TypedArray、Map 和 Set 都是内置可迭代对象,因为它们的原型对象都拥有一个 Symbol.iterator 方法。
2.生成器
生成器是使用function*表达式编写,最初调用时,生成器函数不执行任何代码,而是返回一种称为 Generator 的迭代器,直到遇到yield关键字。
function* makeRangeIterator(start = 0, end = Infinity, step = 1) {
for (let i = start; i < end; i += step) {
yield i;
}
}
var a = makeRangeIterator(1,10,2)
a.next() // {value: 1, done: false}
a.next() // {value: 3, done: false}
a.next() // {value: 5, done: false}
a.next() // {value: 7, done: false}
a.next() // {value: 9, done: false}
a.next() // {value: undefined, done: true}
从上述代码中看出,当遇到yield关键字则生成器的给value赋值,当不满足的时候done返回的是true则终止,而且生成器有一个next方法,这个方法每次执行为上一次断点之后。
三、lssues处理
在看源码时,发现有人提出了这么一个问题,对象中定义了一个不规则的迭代器时,这个转化就会报错,这是因为typeof value[Symbol.iterator]判断不规则的迭代器也是function,所以会出现这个错误,MDN上也写了“如果一个迭代器 @@iterator 没有返回一个迭代器对象,那么它就是一个不符合标准的迭代器。这样的迭代器将会在运行期抛出异常,甚至出现非常诡异的 Bug”。
那么这里就考虑,如果它是一个不规则的迭代器,那么它就没有next方法,那么我们只需要判断它的next方法是不是一个function就行了。
改造后的源码如下:
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' && typeof value.next === "function") {
return [...value];
}
return [value];
}
import arrify from "arrify";
let iterable = {
0: "a",
1: "b",
2: "c",
length: 3,
[Symbol.iterator]: () => 1,
};
console.log(arrify(iterable));
// Expected output:[
{
'0': 'a',
'1': 'b',
'2': 'c',
length: 3,
[Symbol(Symbol.iterator)]: [Function: [Symbol.iterator]] // 这里是直接放入这个迭代器
}
]
四、总结
通过学习这段源码,源码其实很简单,但是这里就涉及到迭代器和生成器两块知识点,这块知识在实际项目开发中很少使用到,所以之前是一直知道这个概念,但是不知道是什么意思,通过这次学习也深化了解了这块的知识。