-
本文已参与「新人创作礼」活动,一起开启掘金创作之路。
-
本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
-
这是源码共读的第33期,链接:【若川视野 x 源码共读】第33期 | arrify 转数组 - 掘金 (juejin.cn)。
** arrify是将任意类型的值转为数组的类型的库。**
源码
// arrify函数接收一个参数value
export default function arrify(value) {
// value为 null 或 undefined 时, 返回一个空数组
if (value === null || value === undefined) {
return [];
}
// value 本身为数组类型, 返回 value 这个数组
if (Array.isArray(value)) {
return value;
}
// value 为字符串, 则返回一个包含该字符串的一维数组
if (typeof value === 'string') {
return [value];
}
// 当 传入的value可迭代对象, 拥有迭代器属性, 返回一个包含该对象所有元素的数组
if (typeof value[Symbol.iterator] === 'function') {
return [...value];
}
// 不是null/undifined, 也不是数组/字符串/可迭代对象
return [value];
}
Symbol.iterator 迭代器 在JS中一些内置类型拥有默认的迭代器行为(即内部包含Symbol.iterator属性), 包括 array typedArray string map set 但是 object 并没有这一特性
let arr = [1,2,33,4]
let it = arr[Symbol.iterator]()
console.log(it.next())
上面的代码定义了一个数组arr,调用了Symbol.iterator方法,这个方法内部还存在next方法。
返回了一个含有value 和done属性的对象
- value ,迭代器返回的当前值,done为true则为undefined
- done,是不是已经到了结尾,是一个布尔值,如果为true则意味着迭代结束
对象中没有Symbol.iterator这个属性,所以对象无法用for...of...
var obj = {name: 'hello'}
var ele = obj[Symbol.iterator]()
console.log(ele)
// => Uncaught TypeError: obj[Symbol.iterator] is not a function
那如何在对象中实现迭代器功能,理解迭代器的结构。
const obj = {
name: 'hello world',
age: 18,
child: ['xiaoqing', 'xiaowen'],
// 在这里定义iterator属性,这个属性是一个函数
[Symbol.iterator](){
let index = 0;
let _this = this;
// 这个函数返回一个next函数
return {
next: function(){
if(index < this.child.length){
const res = { value: this.child[index], done: false };
index++;
return res;
} else {
return { value: undefined, done: true };
}
}
}
}
}
typeof obj[Symbol.iterator] 值为function,说明obj是一个具有迭代器的数据类型。
在对象原型链上添加[Symbol.iterator]属性,使所有对象拥有迭代器属性。
// 给所有对象添加迭代器
Object.prototype[Symbol.iterator] = function(){
let index = 0;
return {
// 箭头函数的this指向当前对象
next:() => {
// 获取对象的所有键值
let keys = Object.keys(this)
return {
value: this[keys[index++]],
done: index > keys.length
}
}
}
}
补充:
测试数据: let value = 'test'
if (typeof value === 'string') { return [value]; }
上面的代码结果加上返回的结果是 ['test'].
如果上面的代码不加的话,会对字符串 test 进行
value[Symbol.iterator] === 'function'判断,用for...of 先将字符串展开,再拼接成数组,结果为['t','e','s','t']
疑问:
为什么将数组类型拿出来判断?
我的思考是,数组类型是具有迭代属性的,如果用value[Symbol.iterator] === 'function'判断的话,再遍历一遍,会浪费性能。
总结
-
学习
arrify源码,将任意类型的数据转为数组类型 -
学习
Symbol.iterator迭代器属性 -
了解
xo、tsd、ava,真的只是了解,后期自己再补上笔记 -
看完源码后再写笔记,确实比收获要很多很多,理解也更透彻许多。之前自己也试着读源码,效率不高,也很难坚持。
-
源码包含的知识点很多,带着疑问学习,进步更大
-
笔记也是对自己每一次学习成果的一种验证