手写源码 -- arrify 转数组
上一篇文章写了omit.js 剔除对象中的属性,相对而言比较简单。这一篇实现一个比较简易的库。
添加测试文件
依然和上篇文章一样,使用vitest
测试,具体怎么操作可以移步上一篇文章,这里我们就只写写测试文件了。
import { test, expect } from "vitest"
import { arrify } from "."
test("main", () => {
expect(arrify("foo")).toEqual(["foo"])
expect(arrify(null)).toEqual([])
expect(arrify(undefined)).toEqual([])
expect(arrify([1, 2])).toEqual([1, 2])
expect(arrify(new Map([[1, 2]]))).toEqual([[1, 2]])
expect(arrify(new Set([1, 2]))).toEqual([1, 2])
})
实现arrify
毫无疑问我们需要实现一个arrify
函数并导出,并且需要传入参数。
传入字符串
首先看这个测试
expect(arrify("foo")).toEqual(["foo"])
arrify
传入一个字符串,返回的是一个数组,而且这个数组将我们传入的字符串包裹起来。那我们可以很简单的实现出来。
export function arrify(value) {
if (typeof value === "string") {
return [value]
}
}
传入null
或undefined
下面看下这个测试
expect(arrify(null)).toEqual([])
expect(arrify(undefined)).toEqual([])
如果传入的是null
或者undefined
则直接返回[]
export function arrify(value) {
if (value === null || value === undefined) {
return []
}
···
}
传入数组
expect(arrify([1, 2])).toEqual([1, 2])
如果传入的是数组,则直接返回
export function arrify(value) {
···
if (Array.isArray(value)) {
return value
}
···
}
可迭代对象
expect(arrify(new Map([[1, 2]]))).toEqual([[1, 2]])
expect(arrify(new Set([1, 2]))).toEqual([1, 2])
这里要着重介绍一下。Symbol.iterator
为每一个对象定义了默认的迭代器。当需要对一个对象进行迭代时(比如开始用于一个for..of
循环中),它的@@iterator
方法都会在不传参情况下被调用,返回的迭代器
用于获取要迭代的值。
一些内置类型拥有默认的迭代器行为,其他类型(如 Object
)则没有。下表中的内置类型拥有默认的@@iterator
方法:
Array.prototype[@@iterator]()
TypedArray.prototype[@@iterator]()
String.prototype[@@iterator]()
Map.prototype[@@iterator]()
Set.prototype[@@iterator]()
我们可以像下面这样创建自定义的迭代器:
var myIterable = {}
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
[...myIterable] // [1, 2, 3]
所以我们想要让测试通过就可以判断value[Symbol.iterator]
的类型是不是function
即可
export function arrify(value) {
···
if (typeof value[Symbol.iterator] === "function") {
return [...value]
}
}
总结
以上就是我实现的一个手写arrify
库。在手写过程中,会有很多自己的想法,思考测试该怎么写,思考代码该怎么重构,更重要的是你真的懂了源码,把它写下来就变成你自己的了。刚开始手写的库比较简单,后面会不断的给自己加大难度。
欢迎大家提出建议和意见,觉得还可以的话,点个赞。 github地址 欢迎大家来个star
转载自:https://juejin.cn/post/7143239847421935624