【若川视野 x 源码共读】第33期 | A13 |arrify 转数组

119 阅读3分钟

注:本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与,本文仅用于学习和交流;

源码如下:

// 将任意值转为数组形式
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逻辑判断;

第一处if判断是否有存在值,此处使用全等===判断,此处说下=====的区别

    let num = 0    let str = ""    let f = false    console.log(num == null) // false    console.log(str == null) // false    console.log(num == undefined) // false    console.log(str == undefined) // false    console.log(num == str) // true    console.log(num == f) // true    console.log(num === str) // false    // 注意后面三组,你会发现 == 和 === 的不同点

参考mdn中解析;MDN中相等

等于运算符(==)检查其两个操作数是否相等,并返回Boolean结果。与严格相等运算符(===)不同,它会尝试强制类型转换并且比较不同类型的操作数。

console.log(1 == 1);
// expected output: true

console.log('hello' == 'hello');
// expected output: true

console.log('1' ==  1);
// expected output: true

console.log(0 == false);
// expected output: true

MDN中有更多详细的其他案例,可自行查看;

第二处if判断是否是数组,此处使用数组的方法Array.isArray();

Array.isArray() 用于确定传递的值是否是一个 Array

    let num = 0    let arr = []    let arr1 = [1, 2, 3]    console.log(Array.isArray(num)) // false    console.log(Array.isArray(arr)) // true    console.log(Array.isArray(arr1)) // true

第三处if判断是否是字符串,此处我不太理解判断这里判断字符串,此处使用typeof来判断;

typeof 操作符返回一个字符串,表示未经计算的操作数的类型。

// 数值
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof(42) === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 尽管它是 "Not-A-Number" (非数值) 的缩写
typeof Number(1) === 'number'; // Number 会尝试把参数解析成数值

typeof 42n === 'bigint';


// 字符串
typeof '' === 'string';
typeof 'bla' === 'string';
typeof `template literal` === 'string';
typeof '1' === 'string'; // 注意内容为数字的字符串仍是字符串
typeof (typeof 1) === 'string'; // typeof 总是返回一个字符串
typeof String(1) === 'string'; // String 将任意值转换为字符串,比 toString 更安全


// 布尔值
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(1) === 'boolean'; // Boolean() 会基于参数是真值还是虚值进行转换
typeof !!(1) === 'boolean'; // 两次调用 ! (逻辑非) 操作符相当于 Boolean()


// Symbols
typeof Symbol() === 'symbol';
typeof Symbol('foo') === 'symbol';
typeof Symbol.iterator === 'symbol';


// Undefined
typeof undefined === 'undefined';
typeof declaredButUndefinedVariable === 'undefined';
typeof undeclaredVariable === 'undefined';


// 对象
typeof {a: 1} === 'object';

// 使用 Array.isArray 或者 Object.prototype.toString.call
// 区分数组和普通对象
typeof [1, 2, 4] === 'object';

typeof new Date() === 'object';
typeof /regex/ === 'object'; // 历史结果请参阅正则表达式部分


// 下面的例子令人迷惑,非常危险,没有用处。避免使用它们。
typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String('abc') === 'object';

// 函数
typeof function() {} === 'function';
typeof class C {} === 'function'
typeof Math.sin === 'function';

// JavaScript 诞生以来便如此
typeof null === 'object';

第四处if判断是否是函数,此处使用typeof和Symbol.iterator判断对象是否是一个可迭代对象,返回的值再解构;

Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。

包含Symbol.iterator属性的对象被称为可迭代对象(Iterable),Symbol.iterator是一个特殊的内置
符号,它的值是一个返回迭代器的方法。ES6内置了多种可迭代对象,例如集合(ArrayTypedArraySetMap)、类数组对象(ArgumentsNodeList)、字符串等,它们都含有各自默认的迭代器。

展示语法...

展开语法 (Spread syntax), 可以在函数调用/数组构造时,将数组表达式或者 string 在语法层面展开;还可以在构造字面量对象时,将对象表达式按 key-value 的方式展开。(译者注: 字面量一般指 [1, 2, 3] 或者 {name: "mdn"} 这种简洁的构造方式)

var arr = [1, 2, 3];
var arr2 = [...arr]; // like arr.slice()
arr2.push(4);

// arr2 此时变成 [1, 2, 3, 4]
// arr 不受影响

提示: 实际上,展开语法和 Object.assign() 行为一致,执行的都是浅拷贝 (只遍历一层)。如果想对多维数组进行深拷贝,下面的示例就有些问题了。

var a = [[1], [2], [3]];
var b = [...a];
b.shift().shift(); // 1
// Now array a is affected as well: [[2], [3]]

具体可参考MDN解析:MDN展开语法