likes
comments
collection
share

从 [] + [],[] + {},{} + [] , {} + {} 深入至对象隐式转换

作者站长头像
站长
· 阅读数 13

二元操作符 + 规则

  • 如果操作数是对象,则对象会转换为原始值
  • 如果操作数是字符串,则另一个操作数也会变成字符串,进行字符串拼接
  • 否则,两个操作数都将转换为数字或 NaN,进行加法操作

对象数据转为原始数据类型值的方法

  • Symbol.ToPrimitive
  • Object.prototype.valueOf
  • Object.prototype.toString

优先级

  • 如果 [Symbol.toPrimitive](hint)方法存在,优先调用,无视 valueOftoSting 方法
  • 否则,如果期望是 "string" —— 先调用 obj.toString() 如果返回不是原始值,继续调用 obj.valueOf()
  • 否则,如果期望是 "number""default" 先调用 obj.valueOf() 如果返回不是原始值,继续调用 obj.toString()
  • 如果未定义[Symbol.toPrimitive](hint),期望string,此时 toString()valueOf() 都没有返回原始值会抛出异常
const obj = {
  value: 10,
  valueOf() {
    return this;
  },
  toString() {
    return this;
  }
};

console.log("hello" + obj); // 报错

[] 的原始值

typeof [][Symbol.ToPrimitive]  // undefined
[].valueOf // []
[].toString() // ""

{} 的原始值

typeof {}[Symbol.ToPrimitive]  // undefined
{}.valueOf() or ({}).valueof() // {}
({}).to String()  // '[object Object]'

[] + []

转换步骤:

  1. [].toString() + [].toString()
  2. "" + ""
  3. ""

[] + {}

  1. [].toStrin() + ({}).toString()
  2. "" + "[object Object]"
  3. "[object Object]"

{} + []

  1. {}; + []
  2. +[]
  3. +""
  4. 0

{} + {}

  1. {}; + {}
  2. +'[object Object]'
  3. NaN

注意之前 chrome 内核浏览器会将其分组后变成 ({} + {}) 转换为变为 '[object Object][object Object]'

Symbol.toPrimitive(hint)

  1. hint(暗示期望)- "string"
  2. hint "number"
  3. hint "default"

hint "string"

  • window.alert(obj)
  • 模板字符串 `${obj}
  • test[obj] = 123
const obj = {
  [Symbol.toPrimitive](hint) {
    if (hint === "number") {
      return 10;
    }

    if (hint === "string") {
      return "hello";
    }

    return true;
  }
};

window.alert(obj); // "hello"

console.log(`${obj}`); // "hello"
obj[obj] = 123;
console.log(obj); // {hello: 123, Symbol(Symbol.toPrimitive): ƒ}
console.log(Object.keys(obj)); // [ "hello" ]

hint "number"

  • 一元+ ,位移
  • -*/ 等算数运算符
  • Math.powStringprototype.slice 等很多内部方法
const obj = {
  [Symbol.toPrimitive](hint) {
    if (hint === "number") {
      return 10;
    }

    if (hint === "string") {
      return "hello";
    }

    return true;
  }
};

console.log("一元+", +obj);
console.log("位移运算符", obj >> 0);
console.log("加法", obj + 5); // 注意加法的 hint 是 default
console.log("减法", obj - 5);
console.log("乘法", obj * 5);
console.log("除法", obj / 5);
console.log("大于:", obj > 5);
console.log("大于:", obj < 5);
console.log("大于等于:", obj >= 5);
console.log("大于等于:", obj <= 5);
console.log("大于等于:", obj !== 5);
// 其他期望是整数的方法
console.log("Math.pow", Math.pow(2, obj));

打印结果:

从 [] + [],[] + {},{} + [] , {} + {} 深入至对象隐式转换

hint - "default"

  • 二元+
  • ==!=
const obj = {
  [Symbol.toPrimitive](hint) {
    if (hint === "number") {
      return 10;
    }

    if (hint === "string") {
      return "hello";
    }

    return true;
  }
};

console.log("相加", obj + 5); // 相加 6
console.log("等等与", obj == 5); // 等等与 false
console.log("不等于", obj != 5); // 不等于 true