|
JavaScript 是如何决定应用哪种转换的?
类型转换在各种情况下有三种变体。它们被称为 “hint”,在 规范 所述:
"string"
对象到字符串的转换,当我们对期望一个字符串的对象执行操作时,如 “alert”:
// 输出
alert(obj);
// 将对象作为属性键
anotherObj[obj] = 123;
"number"
对象到数字的转换,例如当我们进行数学运算时:
// 显式转换
let num = Number(obj);
// 数学运算(除了二元加法)
let n = +obj; // 一元加法
let delta = date1 - date2;
// 小于/大于的比较
let greater = user1 > user2;
大多数内建的数学函数也包括这种转换。
"default"
在少数情况下发生,当运算符“不确定”期望值的类型时。
例如,二元加法 + 可用于字符串(连接),也可以用于数字(相加)。因此,当二元加法得到对象类型的参数时,它将依据 "default" hint 来对其进行转换。
此外,如果对象被用于与字符串、数字或 symbol 进行 == 比较,这时到底应该进行哪种转换也不是很明确,因此使用 "default" hint。
// 二元加法使用默认 hint
let total = obj1 + obj2;
// obj == number 使用默认 hint
if (user == 1) { ... };
像 < 和 > 这样的小于/大于比较运算符,也可以同时用于字符串和数字。不过,它们使用 “number” hint,而不是 “default”。这是历史原因。
上面这些规则看起来比较复杂,但在实践中其实挺简单的。
除了一种情况(Date 对象,我们稍后会讲到)之外,所有内建对象都以和 "number" 相同的方式实现 "default" 转换。我们也可以这样做。
尽管如此,了解上述的 3 个 hint 还是很重要的,很快你就会明白为什么这样说。
为了进行转换,JavaScript 尝试查找并调用三个对象方法:
调用 obj[Symbol.toPrimitive](hint) —— 带有 symbol 键 Symbol.toPrimitive(系统 symbol)的方法,如果这个方法存在的话,
否则,如果 hint 是 "string" —— 尝试调用 obj.toString() 或 obj.valueOf(),无论哪个存在。
否则,如果 hint 是 "number" 或 "default" —— 尝试调用 obj.valueOf() 或 obj.toString(),无论哪个存在。
|
|