- 本文已参与「新人创作礼」活动,一起开启掘金创作之路。
- 本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
- 这是源码共读的第33期,链接:【若川视野 x 源码共读】第33期 | arrify 转数组 - 掘金 (juejin.cn)。
arrify这个包为开发者提供了一种非常简单快捷的数据转数组方法。
使用演示
arrify('🦄');
//=> ['🦄']
arrify(['🦄']);
//=> ['🦄']
arrify(new Set(['🦄']));
//=> ['🦄']
arrify(null);
//=> []
arrify(undefined);
//=> []
源码
来看一下这个包是怎么样实现这个功能的.
前置知识: ES6中的iterator
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];
}
前三个if判断非常简单,它们的规则是:
- Null 和 Undefined 返回空数组
- 数组类型直接返回本身
- String 类型直接用数组包起来
重点在于最后一个if判断.
函数的参数value传入的值可能是任何的数据类型,value[Symbol.iterator]这句话的意思就是拿到value里面的Symbol.iterator属性。
你可以这样理解,对于普通的对象,对象中的属性键名都是字符串,所以你在调用对象中的属性时,使用的方式是对象名.属性,而Symbol.iterator在数据中存储形式是变量,要想取到这个变量,不能直接通过"."获得,因为这不是一个字符串,你应该使用中括号获得这个属性.
关于迭代器
在JavaScript中一些内置类型拥有默认的迭代器行为(即内部包含Symbol.iterator属性),包括
- array
- typedArray
- string
- map
- set
但object并没有这一特性.
当你访问Symbol.iterator这一属性时,你将会获得一个next()函数,如果你对这一知识点不熟悉,请先学习ES6中的iterator.
在这里展示了在对象中实现迭代器功能,你可以从中理解迭代器到底是什么结构.
const banji = {
name: 'hahaha',
stu: [
'xiaoming',
'xiaohong'
],
// 在这里定义iterator属性,这个属性是一个函数
[Symbol.iterator]() {
let index = 0;
let _this = this;
//这个函数将会返回一个next函数
return {
next: function () {
if (index < this.stu, length) {
const res = { value: this.stu[index], done: false };
index++;
return res;
} else {
return { value: undefined, done: true };
}
}
};
}
};
因此,在typeof value[Symbol.iterator]的语句中,如果值为function,就说明value是一个具有迭代器的数据类型.
于是转换数组的方法是使用扩展运算符,把数据中的属性放到数组中.
而对于其它类型的数据,直接用数组包裹起来即可.
我学到了: typeof value[Symbol.iterator] === 'function'可以用来判断一个数据是否具有迭代器