对象类型转换
上文介绍完了显式类型和隐式类型的转化,详情点击:理解 JavaScript 的显式类型转换和隐式类型转换https://blog.csdn.net/qq_24956515/article/details/143104712
下面来看看对象类型的转化。例如,当执行 obj_1 + obj_2
或者 obj_1 - obj_2
时,都会先将对象转换为原始类型,然后将其转换为最终类型。当然,这里的转化仍然只有三种类型:数字、字符串和布尔值。
对象通过内部的 ToPrimitive
方法将其转换为原始类型,该算法允许我们根据使用对象的上下文来选择应如何转换对象。从概念上讲,ToPrimitive 算法可以分为两部分:Hints 和 Object-to-primitive 转换方法。
1. Hints
Hints 是 ToPrimitive
算法用于确定对象在特定上下文中应转换为什么的信号。有三种情况:
string
:在操作需要字符串的上下文中,如果可以转换为字符串,例如 alert()
或内置 String()
函数:
alert(obj);
String(obj)
// 使用对象作为属性key值
anotherObj[obj] = 1000;
number
:如果可以进行这种转换,则在操作需要数字的上下文中:
// 显示转换
let num = Number(obj);
// 数学(二进制加号除外)
let x = +obj; // 一元加
let difference = Date1 - Date2; // 日期对象
// 对象大小比较
let less = Obj1 < obj2;
default
:在极少数情况下发生,不确定需要什么类型。例如,二元 + 运算符既适用于字符串(连接它们)也适用于数字(添加它们)。在这种情况下,对象可以转换为字符串或数字。 或者当使用宽松相等 == 运算符将对象与字符串、数字或 symbol 进行比较时。
// 二元加
let sum = obj1 + obj2;
// obj == string/number/symbol
if (obj == 10 ) { ... };
所有内置对象(日期除外)都将default
认为是number
,Date 日期对象将default
认为是string
。
2. Methods
在 ToPrimitive 算法根据 Hints
确定对象应转换为的原始值类型之后。 然后使用 Object-to-primitive 转换方法将对象转换为原始值。有三种情况:
-
toString/valueOf
:toString()
和valueOf()
被 JavaScript 中的所有对象继承。 它们仅用于对象到原始值的转换。 ToPrimitive 算法首先会尝试toString()
方法。 如果定义了方法,它返回一个原始值,那么 JavaScript 使用原始值(即使它不是字符串)。 如果toString()
返回一个对象或不存在,那么 JavaScript 会尝试使用valueOf()
方法,如果该方法存在并返回一个原始值,JavaScript 将使用该值。 否则,转换失败并提示TypeError
。 -
toString -> valueOf
:用于 Hints 为string
的情况。 -
valueOf -> toString
:其他情况。
let Person = {
name: "Mary",
age: 22,
// hint 是 "string"
toString() {
return `{name: "${this.name}"}`;
},
// hint 是 "number" 或 "default"
valueOf() {
return this.age;
}
};
alert(Person); // toString -> {name: "Mary"}
alert(+Person); // valueOf -> 22
alert(Person + 10); // valueOf -> 32
在上面的代码中,Person
变成了一个对象字符串或数字,具体取决于转换上下文。 toString()
方法用于 Hints = "string" 的转换,valueOf()
用于其他情况(Hints 为“number”或“default”)。
你可能希望在一个地方处理所有转换。 在这种情况下,只能像这样实现 toString()
方法:
let Person = {
name: "Mary",
toString() {
return this.name;
}
};
alert(Person); // toString -> Mary
alert(Person + 1000); // toString -> Mary1000
Symbol.toPrimitive
:与 toString()
和 valueOf()
方法不同,Symbol.toPrimitive
允许覆盖 JavaScript 中的默认对象到原始值的转换(其中 toString()
和 valueOf
方法由 ToPrimitive 算法使用)并定义我们希望如何将对象转换为原始类型的值。 为此,需要使用此 Symbol 名称定义一个方法,如下所示:
obj[Symbol.toPrimitive] = function(hint) {
// 返回原始类型值
// hint 等于 "string", "number", "default" 中的一个
}
例如,这里的 Person
对象使用 Symbol.toPrimitive
执行与上面相同的操作:
let Person = {
name: "Mary",
age: 22,
[Symbol.toPrimitive](hint) {
alert(`hint: ${hint}`);
return hint == "string" ? `{name: "${this.name}"}` : this.age;
}
};
alert(Person); // hint: string -> {name: "Mary"}
alert(+Person); // hint: number -> 22
alert(Person + 10); // hint: default -> 32
可以看到,单个方法 Person[Symbol.toPrimitive]
处理了所有转换情况。需要注意,在没有 Symbol.toPrimitive
和 valueOf()
的情况下,toString()
将处理所有原始类型转换。
下面是将对象转化为布尔值、字符串、数字时的执行过程:
(1)对象到布尔值的转换
Javascript 中的所有对象都转换为 true,包括包装对象 new Boolean(false) 和空数组。 对象到布尔值的转换不需要对象到原始类型算法。
(2)对象到字符串的转换
当需要将对象转换为字符串时,Javascript 首先使用 ToPrimitive 算法(Hints = “string”)将其转换为原始类型,然后将派生的原始类型转换为字符串。例如,如果将对象传递给 String() 这样的内置函数,或者在模板字符串中插入对象时。
(3)对象到数字的转换
当需要将对象转换为数字时,Javascript 首先使用 ToPrimitive 算法(Hints = “number”)将其转换为原始类型,然后将派生的原始类型转换为数字。 期望数字参数的内置 Javascript 函数和方法以这种方式将对象参数转换为数字,例如 Math()。
3. 特殊情况
当某些 Javascript 运算符的操作数是对象时,也会发生类型转换:
-
+ 运算符: 此运算符可以用于执行数字加法和字符串连接。如果其中任何一个操作数是对象,则使用 ToPrimitive 算法(Hints = “default”)将它们转换为原始值。一旦将它们转换为原始值,就会检查它们的类型。如果任一参数是字符串,则将另一个参数转换为字符串并连接字符串。否则,它将两个参数都转换为数字并将它们相加。
-
== 和 !== 运算符: 这些运算符以宽松方式执行相等和不相等测试。如果一个操作数是一个对象而另一个是一个原始值,这些运算符使用 ToPrimitive 算法(Hints = “default”)将对象转换为原始值,然后比较两个原始值。
-
<,<=,> 和 >= 关系运算符: 关系运算符用于比较两个值之间的关系,可用于比较数字和字符串。如果任一操作数是对象,则使用 ToPrimitive 算法将其转换为原始值(Hints = “number”)。但是,与对象到数字的转换不同,返回的原始值不会转换为数字(因为它们被比较并且不被使用)。