前端小生面试之看不懂的 []+{}

面试滑铁卢

有一天,去面试,遇到这样的题:html

[]+[]
{}+{}
1+[]
复制代码

???WTF,谁会没事这么写代码,好吧,我错了,大佬别打我。懵逼以后要干吗?固然是要学习一波,因而我满世界找资料,有好东西固然是要分享一波,好了,接下来咱们就一块儿走进 JavaScript 隐式转换的世界吧。git

加法运算

在 JavaScript 中加法运算规则很简单,它只作数字和字符串的加法操做,全部不是这两种类型的都会被转换成这两种原始数据类型再进行操做。github

在 JavaScript 中,数据类型分两种:面试

  • 原始数据类型(primitives): undefined, null, boolean, number,string,symbol
  • 其余的都是对象,包括数组、函数。

那么对象是如何转换成原始数据类型的呢?不要慌,咱们继续看。数组

ToPrimitive

JS 有一个内部运算 ToPrimitive(),它用于对象转换为原始数据类型。浏览器

ToPrimitive(input, PreferredType?)
复制代码

这个函数接收两个参数:markdown

  • input: 这个参数是输入的值。
  • PreferredType: 这个参数能够Number 或者是 String,这表明了咱们的对象优先会转换成哪一种原始数据类型。若是缺乏这个参数的话,那对于 Date 的实例,默认为 String,其他的都为 Number。转换的步骤也会由于这个参数而有所不一样。

下面咱们来看一下对于不一样的参数,它的转换过程是什么样的?函数

PreferredType 为 Number

  1. 若是 input 为原始类型,则直接返回 input。
  2. 不然,若是 input 是一个对象,则会去调用对象的 valueOf() 方法,若是结果为原始类型就直接返回。
  3. 若是上一步返回的依然是对象,那么就回去调用对象的 toString() 方法,若是结果为原始数据类型就返回。
  4. 若是还不是原始数据类型就抛出错误,通常是 Uncaught TypeError: Cannot convert object to primitive value

PreferredType 为 String

参数 String 就不细说了,当参数为 String 的时候,上面的第二步和第三步交换就好了,也就是先调用 toString() 再调用 valueOf()oop

+ 运算

value1 + value2
复制代码

上面的操做方式以下:学习

  1. 将两个操做数转换成基本数据类型:
 // PreferredType被省略,所以非日期为 Number,日期为 String。
prim1 = ToPrimitive(value1)
prim2 = ToPrimitive(value2)
复制代码
  1. 若是 prim1 或 prim2 是一个字符串,则将其转换为字符串并返回结果的链接。
  2. 不然,将 prim1 和 prim2 都转换为数字并返回结果的总和。

valueOf 和 toString

这两个都是 Object 的属性,能够本身定义,如今咱们无论,咱们去看看下面几种状况这两个方法返回的都是什么。

// 对象
const a1 = {
  a: 1
};
console.log(a1.valueOf());
console.log(a1.toString());
// 数组
const a2 = [1,2,3];
console.log(a2.valueOf());
console.log(a2.toString());
// 方法
const a3 = function() {
  const a = 1;
  return 1;
};
console.log(a3.valueOf());
console.log(a3.toString());
复制代码

将上面的代码放到控制台打印一下就知道:

  • 对象: valueOf() 返回对象自己,toString() 返回值为 [object Object]。
  • 数组: valueOf() 返回对象自己,数组改写了 toString(),返回值至关于用 join(',') 的返回值,好比 [1,2,3].toString() 返回 "1,2,3"。
  • 方法: valueOf() 返回方法自己,Function 也改写了对象的 toString(),它将代码转为字符串值而后返回。

举个栗子

好了,根据咱们上面说的,那些面试题简直洒洒水,咱们来看。

[]+{}
复制代码

咱们如何去分析呢?在这里,咱们首先将 [] 和 {} 转换成原始数据类型,也就是 ToPrimitive([]) 以及 ToPrimitive({}),PreferredType 默认为 Number,很明显 [].valueOf() 仍是一个对象,因此咱们继续,[].toString() 结果为 "",相同的解析过程 {} 转换成 "[object Object]"。

好了,如今这个式子是 "" + "[object Object]",咱们知道 + 运算只要有字符串就拼接操做数,因此结果是 "[object Object]"。

可是,在我进行测试的时候,发现了几个特殊的例子,{}+1{}+[] 这两个例子在控制台打印出的结果为 1"",很奇怪是吧?我搜了搜资料发现,不一样浏览器对其的解析不一样,它会将前面一个 {} 当成代码块,因而上面的式子就变成了 +1+[],因此得出了上面的结果。

总结

好了,通过上面的探究,我相信你们不会再被这些问题难住了,可是要记住,{} 在前面的状况下可能会由于浏览器的差别会形成不一样的结果,固然,若是你这样将 {} 用 () 包起来就不会有问题了,或者是先声明在使用。

更多资源

更多文章尽在 个人博客仓库,若是各位读者以为有用,欢迎 star,不胜感激。

相关文章
相关标签/搜索