掘金文章归档 · 第 40 篇 JS 进阶系列 5/8 类型转换 · 面试

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

对象的隐性转化逻辑:Symbol.toPrimitive → valueOf → toString

原文作者:随意_(掘金) | juejin.cn/post/7387581960028012594 | 发布于 2024-07-04 | 阅读 152 · 约 2 分钟

0背景

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

📌 []+[] === ""[]+![] === "false"

1一、对象的隐性转化逻辑

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

步骤方法说明
1[Symbol.toPrimitive]先查看是否有该属性,且该属性须是一个函数;有此属性的对象,隐性转化先执行此函数
2valueOf无 [Symbol.toPrimitive] 属性,则走 valueOf 转化逻辑
3toString前两步都没有,或 valueOf 返回的不是基础类型,则走 toString 转义

1. [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') // TypeError: Cannot convert object to primitive value

2. valueOf

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

valueOf 返回基础类型:

const obj = {
  valueOf:()=>{
    return "valueOf"
  }
}
// obj转化为 "valueOf" +"end"
console.log(obj+'end') // valueOfend
⚠️ 如果 valueOf 不返回基础类型,则会走第三步 toString。

3. toString

前两步都没有,或者 valueOf 返回的不是基础类型,则会走 toString 来转义。

const obj = {
  toString:()=>{
    return 'toString'
  }
}
console.log(obj+'end') // toStringend
⚠️ 如果 toString 返回的也不是基础类型,则会报错 TypeError。
const obj = {
  toString:()=>{
    return []
  }
}
console.log(obj+'end') // TypeError: Cannot convert object to primitive value

2二、面试题答案解析

[]+[] 解析

基于以上的对象隐性转化逻辑,我们先分析第一道题:[]+[] 为何等于 "" 空字符串。

我们先看 []+[],会触发对象的隐性转义。按照上述三个步骤,依次看下空数组 [] 隐性转化成什么:

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

[]+![] 解析

通过第一题可知:左侧空数组 [] 转义成空字符串 ""。右侧 ![] 如何转化?

布尔运算完成后再进行隐性转化:[] 的布尔运算为 true,此时 ![] 进行取反操作为 false,上述题目转译成 "" + false,结果为字符串 "false"。

📌 综上:[]+![] 等于 "false"。

3三、总结