本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
源码共读前言
本文目标
- 学习 Symbol.iterator 的使用场景
- 学会通过测试用例调试源码
- 发布npm包
- esm
- 测试用例
源码
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];
}
知识点
1. typeof
主要针对基础类型和对象类型,以及
undefined、null更多参考
2. Symbol.iterator
包括:数组 ( Array ) 和类型数组 ( TypedArray )、Map、Set、String、类数组对象(Arguments、NodeList)
特性:
- 可以应用 for..of 的对象被称为 可迭代的;
- 必须有 next() 方法,它返回一个 {done: Boolean, value: any} 对象,这里 done:true 表明迭代结束,否则 value 就是下一个值。
- Symbol.iterator 方法会被 for..of 自动调用,也可以直接调用它。
根据以上特性,做如下思考:
- 既然string也是可迭代对象,源码中针对string类型的判断是不是可以移除?
- 既然Array也是可迭代对象,源码中针对Array类型的判断是不是可以移除?
测试疑问【1】: 移除string类型的判断后,'foo' 被转为['f','o','o'],不符合需求,显然string此时被当成可迭代对象,遍历出每个字符;故不可移除
测试疑问【2】: 移除Array类型的判断后,经测试未发现异常,所以此处暂时存疑?也可能是提高代码可读性
3. 代码测试Test
测试代码片段
import test from 'ava';
import arrify from './index.js';
test('main', t => {
const stringArray = arrify('foo');
t.deepEqual(stringArray, ['foo']);
t.deepEqual(arrify(new Map([
[1, 2],
['a', 'b']
])), [
[1, 2],
['a', 'b']
]);
t.deepEqual(arrify(new Set([1, 2])), [1, 2]);
t.deepEqual(arrify(null), []);
t.deepEqual(arrify(undefined), []);
const fooArray = ['foo', 1, [1, 'dd']];
const fooArrayResult = arrify(fooArray);
t.is(fooArrayResult, fooArray);
});
命令Test的三个包:xo、tsd、ava(nodejs 测试工具)
xo:JavaScript/TypeScript linter (ESLint wrapper) with great defaults JavaScript/TypeScript linter(ESLint 包装器)具有很好的默认值
tsd:Check TypeScript type definitions 检查 TypeScript 类型定义
ava:Node.js test runner that lets you develop with confidence
总结
- 基础需要稳固,稳固而知新
- 学习源码思想,多想想为什么?多参考他人的笔记思路
- 贵在坚持,勿以善小而不为