从[]+[] 和 []+![]说起,谈谈对象的隐性转化

102 阅读2分钟

背景

最近刷文章一直刷到[]+[][]+![]的面试题,刷某音也刷到了,借助某音老师讲的,留个笔记,记录下对象的隐形转化逻辑,先公布答案 []+[]="" []+![]="false"

对象的隐性转化逻辑

对象的隐性转化逻辑分为三部,按照先后循序依次执行

1:[Symbol.toPrimitive]

首先转化逻辑,先查看是否有 [Symbol.toPrimitive]属性,且这个属性须是一个函数,有此属性的对象,隐性转化先执行此函数,如果此函数返回的不是基础类型,则直接报错TypeError: Cannot convert object to primitive value

[Symbol.toPrimitive]返回基础类型,obj+'end'触发隐性转化
const obj = {
  [Symbol.toPrimitive]:()=>{
    return "toPrimitive"
  }
}
// obj转化为 "toPrimitive" +"end"
console.log(obj+'end') // toPrimitiveend
[Symbol.toPrimitive]返回未基础类型,则直接报错
const obj = {
  [Symbol.toPrimitive]:()=>{
    return []
  }
}
console.log(obj+'end')

image.png

2:valueOf

[Symbol.toPrimitive]属性,则会走valueOf属性转化逻辑,valueOf可以返回基础类型也可不返回基础类型

valueOf返回基础类型
const obj = {
  // [Symbol.toPrimitive]:()=>{
  //   return []
  // }
  valueOf:()=>{
    return "valueOf"
  }
}
// obj转化为 "valueOf" +"end"
console.log(obj+'end') // valueOfend

valueOf不返回基础类型,则会走第三步toString

3:toString

前方2个属性都没有,或者valueOf返回的不是基础类型,则会走toString来转义

const obj = {
  // [Symbol.toPrimitive]:()=>{
  //   return []
  // }
  // valueOf:()=>{
  //   return []
  // }
  toString:()=>{
    return 'toString'
  }
}
console.log(obj+'end') // toStringend

如果toString返回的也不是基础类型,则会报错

const obj = {
  // [Symbol.toPrimitive]:()=>{
  //   return []
  // }
  // valueOf:()=>{
  //   return []
  // }
  toString:()=>{
    return []
  }
}
console.log(obj+'end')

image.png

面试题答案解析

[]+[]解析

基于以上的对象隐性转化逻辑,我们先分析 第一道题 []+[]为何等于""空字符串 我们先看[]+[],会触发对象的隐性转义,我们按照上诉三个步骤,依次看下空数组[]隐性转化成什么

image.png

控制台打印可见:[]不存在[Symbol.toPrimitive]属性, valueOf()返回的是[]不是基础类型,所以走第三步 toString()返回空字符串,综上 []+[]等于""空字符串

[]+![]解析

通过第一题我们我们可知 左侧空数组[]转义成空字符串 "", 右侧 ![]如何转化是布尔运算,布尔运算完成后再进行隐性转化 []的布尔运算为 true

image.png

此时 ![]进行取反操作为 false 此时上述题目转译成 ""+false结果为字符串 "false"

总结

1:对象的隐性转化顺序,1:[Symbol.toPrimitive] 2:valueOf 3:toString

2:隐性转化优先级低于布尔转化 可查看运算符优先级运算符