【第33期】| 15组 | arrify 转数组

271 阅读5分钟

  本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与

  本期要阅读的源码:arrify

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,再则数组判断,最后是可迭代对象。

一、全等

  提起全等,马上就能想到相等。相等(==)和全等(===)这两个运算符都用来判断两个操作数是否相等,但它们之间有一个最大的区别,就是“==”允许在比较中进行类型转换,而“===”禁止类型转换。各种类型之间进行相等比较时,执行的类型转换是不同的,在ECMAScript 5中已经定义了具体的转换规则。下表将规则以表格的形式展示,第一列表示左边操作数“X”的类型,第一行表示右边操作数“Y”的类型。在表格中,Number()函数用简写N()表示,ToPrimitive()函数用简写TP()表示。

  当判断对象和非对象是否相等时,会先让对象执行ToPrimitive抽象操作,再进行相等判断。ToPrimitive抽象操作就是先检查是否有valueOf()方法,如果有并且返回基本类型的值,就用它的返回值;如果没有就改用toString()方法,再用它的返回值。

X == Y数字字符串布尔值nullundefined对象
数字N(Y)N(Y)不等不等TP(Y)
字符串N(X)N(Y)不等不等TP(Y)
布尔值N(X)N(X)N(X)N(X)N(X)
null不等不等N(Y)相等相等TP(Y)
undefined不等不等N(Y)相等相等TP(Y)
对象TP(X)TP(X)N(Y)TP(X)TP(X)

二、typeof

  typeof运算符能检测出6种内置类型和函数,执行完后会返回一个小写字母的类型字符串,检测规则如下所列,在每条规则旁还会给出相应的示例代码。

  1. 当检测基本类型中的数字、字符串或布尔值时,会分别返回“number”、“string”、“boolean”和“symbol”,下面会检测3种类型的值,包括一些特殊的值。
//返回"number"
typeof 1; 		//整数
typeof 1.5; 		//浮点数
typeof Infinity; 	//无穷大
typeof NaN; 		//不是数字的数值
typeof Number("1"); //类型转换
//返回"string"
typeof "1"; 		//字符串字面量
typeof ""; 		//空字符串
typeof String(1); 	//类型转换
//返回"boolean"
typeof true; 		//真值
typeof false; 		//假值
typeof Boolean(1); 	//类型转换
//返回“symbol”
typeof Symbol();
  1. 当检测基本类型中的undefined时,会返回“undefined”。
typeof undefined; 	//"undefined"
  1. 当检测基本类型null时,不是返回“null”,而是返回“object”。
typeof null; 		//"object"
  1. 当检测函数时,会返回“function”。
function func() {}
typeof func; 		//"function"
  1. 当检测除了函数之外的对象时,都会返回“object”,下面对常用的对象执行typeof运算符。
typeof {name:"strick"}; //对象字面量
typeof [1, 2]; 		//数组字面量
typeof /\s/; 		//正则表达式字面量
typeof new Date(); 	//日期对象
typeof new Number("1"); //数字对象
typeof new String(1); 	//字符串对象
typeof new Boolean(1); 	//布尔值对象

三、toString()

  Array.isArray()用于判断参数是否是数组,此方法在ES6中正式引入,在此之前,可以通过toString()来判断参数是否是数组类型。

  typeof运算符是检测数字、字符串、布尔值、函数和undefined的最佳工具,但如果要区分对象中的类型,例如数组、日期等,就无能为力了,得换一种检测工具。在基础对象Object的原型上有个toString()方法,它能返回格式为“[object Type]”的字符串,其中Type是对象的类型,此方法能检测出的对象有Number、Array、Date、RegExp等。有一点需要注意,就是虽然每个对象都继承了toString()方法,但不能直接使用,因为对象有可能重写了此方法,必须使用函数的方法call()或apply()间接调用toString(),下面是toString()的用法。

var toString = Object.prototype.toString;
toString.call({}); 		//"[object Object]"

  传入不同类型的值,其检测规则也会有所不同,具体如下所列,在每条规则旁还会给出相应的示例代码。

  1. 如果传入的是原始值,那么会先转换为对应的包装对象,再进行检测。
toString.call(1); 		//"[object Number]"
toString.call("1"); 		//"[object String]"
toString.call(true); 		//"[object Boolean]"
  1. 如果传入null,那么Type对应的值为“Null”。
toString.call(null); 		//"[object Null]"
  1. 如果传入undefined,那么Type对应的值为“Undefined”。
toString.call(undefined); 	//"[object Undefined]"
  1. 如果传入其它对象,那么Type对应的值为“Number”、“Array”等对象的类型,下面将toString()方法作用于常用的对象。
function func() {}
toString.call(func); 			//"[object Function]"
toString.call({ name: "strick" }); 	//"[object Object]"
toString.call([1, 2]); 			//"[object Array]"
toString.call(/\s/); 			//"[object RegExp]"
toString.call(new Date()); 		//"[object Date]"
toString.call(new TypeError()); 	//"[object Error]"

四、可迭代对象

  包含Symbol.iterator属性的对象被称为可迭代对象(Iterable),Symbol.iterator是一个特殊的内置符号,它的值是一个返回迭代器的方法。ES6内置了多种可迭代对象,例如集合(Array、TypedArray、Set和Map)、类数组对象(Arguments和NodeList)、字符串等,它们都含有各自默认的迭代器。下面的示例使用了数组的默认迭代器,通过next()方法依次遍历了它所包含的元素,返回结果与上一个示例类似。

var arr = ["a", "b"],
  iterator = arr[Symbol.iterator]();
iterator.next();        //{value: "a", done: false}
iterator.next();        //{value: "b", done: false}
iterator.next();        //{value: undefined, done: true}

  可迭代对象的应用场景包括扩展运算符、解构赋值和Array.from()方法等。

参考资料:

前端程序员面试笔试宝典

前端躬行记