- 本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
- 这是源码共读的第# 33 期,链接:arrify 转数组。
阅读源码的意义
我们为什么要阅读源码, 这是我曾经思考的问题, 因为我知道阅读源码并不是一件简单轻松的事情, 它有可能需要花费我巨大的时间并且会让我陷入思考,属于给自己找事,在平时工作中我明明只需要会使用就好了。直到我遇到了一个人,在相同的问题上,他总可以提出一个更优解的感觉,并且他一直给我推荐各种优秀的开源框架。我问他为什么我们需要看这些源码,源码不是仅仅在面试中一对一答中使用的吗,在平时工作中我们不懂它底层的实现还是可以通过文档使用。他告诉我,面试是一部分,但阅读源码你不仅可以学习到你当初薄弱或不懂得知识,也可以学习更加优雅的解决方案。我听完他得话后觉得挺有道理得,但是源码大型框架得源码对我来说还是太吃力,我为了弥补基础看了 JS 最著名的红宝书, 后面我发现我关注的公众号 若川视野 有发起一个源码共读的活动所以我参与进来了, 若川给刚刚开始阅读源码的我,推荐了第一个库 arrify.js
克隆源码
git clone https://github.com/sindresorhus/arrify.git
开始阅读源码之前我需要把代码给克隆到本地
使用 arrify.js
克隆到本地后, 第一步当然并不是开始阅读源码, 首先我需要弄懂这个库解决的是什么问题,如何使用,可以通过阅读 readme.md 文件,按照作者的步骤最简单的使用起来,通过 readme.md 文件我可以发现这个库提供了函数将任意值转成一个数组类型作为返回
阅读源码
当了解使用, 我就开始步入正题阅读源码上面, 虽然我在阅读源码之前也想了方案可以实现此功能,这样我就可以对比和作者在实现上的不同,他有没有更加优秀的方法呢?
在点开 index.js 文件后, 我发现源码相当简单就是暴露了 arrify 函数, 将任意值返回成数组类型, 只有简单的 19 行, 这其中还包括了为了阅读性加的换行, 我感觉大为震惊, 因为在我印象中源码都是至少上千行这种。
之后我将我的注意力重新放在实现上,发现作者的想法和我一样放在类型判断上, 这里贴一下作者的源码实现
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];
}
前面的判断都是很简单的, 直到这一行 typeof value[Symbol.iterator] === 'function' 上, 作者很巧妙的判断了当前数据类型是否实现了 Symbol.iterator 方法, 然后用扩展运算符, 将 value 扩展在一个新数组中返回, 因为我之前有阅读 Js 红宝书, 所以知道 Symbol.iterator 的作用,所以这次阅读源码对于我来说还是比较简单的。
他这样写有什么好处呢,我第一时间就想到了在处理 伪数组 上更加简单只需要判断当前数据类型是否实现了 Symbol.iterator 然后用 es6 新增的扩展运算符就可以很方便的将该类型转换成数组类型, 因为在数组中使用扩展运算符就是调用了当前数据类型的 Symbol.iterator 属性上的方法
拓展
Symbol.iterator 首先我们可以查 MDN 上面的简介: Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。在这我们可以看到 Symbol.iterator 最简单的使用
var myIterable = {}
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
[...myIterable] // [1, 2, 3]
他就是在一个 myIterable 对象上实现了自己的 Symbol.iterator 属性, 这个属性需要一个返回迭代器对象的方法, 而生成器函数就完美符合, 所以完美看见他实现的方法关键字 function 后面跟了一个 * 号, 这就代表当前函数是一个生成器, 关于生成器和迭代器, 推荐大家阅读JavaScript 高级程序设计最新版本的迭代器和生成器这一章节, 里面有非常详细的解释
总结
在 arrify.js 源码阅读上, 我发现了阅读源码可以让我有解决一个问题上更好的方案,顺便复习我之前的知识点, 这个库的作者利用了当前类型是否实现了 Symbol.iterator 来判断当前数据是否可扩展, 是一个非常巧妙的解决方案,让我见识到了 Symbol.iterator 另一种方式的应用方式, 希望自己可以坚持下来, 不断提升自己。