1、隐式转换
++我们知道js式弱类型语言,这意味着当操作涉及不匹配的类型,它将允许隐式类型转换,而不是抛出一个错误。++
原始值转换会在 toString()
方法之前调用 valueOf()
方法,这与强制数字类型转换的行为相似,但与强制字符串类型转换不同。
1、Symbol.toPrimitive
Symbol.toPrimitive
是内置的 symbol 属性,其指定了一种接受首选类型并返回对象原始值的表示的方法。它被所有的强类型转换制算法优先调用。
在 Symbol.toPrimitive
属性(用作函数值)的帮助下,对象可以转换为一个原始值。该函数被调用时,会被传递一个字符串参数 hint
,表示要转换到的原始值的预期类型。hint
参数的取值是 "number"
、"string"
和 "default"
中的任意一个。
对于hint==='default'
发生类型转换的情况如下:
Date()
构造函数,当它收到一个不是Date
实例的参数时------字符串表示日期字符串,而数值表示时间戳。+
运算符------如果运算对象是字符串,执行字符串串联;否则,执行数值相加。==
运算符------如果一个运算对象是原始值,而另一个运算对象是对象(object),则该对象将转换为没有首选类型的原始值。
如果值已经是原始值,则此操作不会进行任何转换。对象按以下顺序调用它的 [@@toPrimitive]()
(将 hint 作为 default
)、valueOf()
和 toString()
方法,将其转换为原始值。
对于hint==='number'
则执行强制数字类型转换算法
对于数字类型有两类:number和BigInt
number
强转,执行Number()
*
对于hint==='string'
用于强制字符串类型转换算法
- 使用
String()
强转
:::tip
[Symbol.toPrimitive](hint)
由引擎调用,那什么时候hint
为number
,string
或default
呢
js
const object1 = {
[Symbol.toPrimitive](hint) {
console.log(hint)
},
};
// 当执行 +object1 hint = number
// 当执行 `${obj2}` hint = string
// 其余情况 hint=default
:::
2.隐式转换示例
js
console.log({} + []); // "[object Object]"
{}
和 []
都没有 [@@toPrimitive]()
方法。因此会调用valueOf
方法,而valuieOf
返回对象自身,由于返回值还是对象,因此继续调用toString
方法,{}.toString()
返回"[object Object]"
而[].toString()
返回是空字符串
js
{} + {}
//NAN
({} + {})
'[object Object][object Object]'
第一次看到这个结果我懵了,想不到原因,最后查看资料,发现JavaScript 把第一个 {}
解释成了一个空的代码块(code block)并忽略了它。 NaN
其实是表达式 +{}
计算的结果 (+
加号以及第二个 {}
)。 你在这里看到的 +
加号并不是运算符「加法」,而是一个一元运算符,作用是将它后面的操作数转换成数字,和 Number()
函数完全一样。为什么第一个 {}
会被解析成代码块(code block)呢? 因为整个输入被解析成了一个语句:如果左大括号出现在一条语句的开头,则这个左大括号会被解析成一个代码块的开始。
js
{} + []
0
/*转换流程如下
+[]
[].valueOf()//不是原始值
[].toString()
Number([].toString())
Number("")
0
*/
js
[1,2]+[3,4]
//'1,23,4'
//[1,2].toString()+[3,4].toString() = '1,2'+'3,4'
3.Number强制类型转换
Number()操作如下:
-
Number 将按原样返回
-
undefined 转换为 NaN。
-
null 转换为 0。
-
true 转换为 1;false 转换为 0。
-
字符串将被假定为包含数字字面量,并通过解析它们来转换。解析失败会得到 NaN。与实际数字字面量相比,它们有一些细微的差别:
-
前导和尾随的空格/换行符会被忽略。
-
前导的数字 0 不会导致该数值成为八进制字面量(或在严格模式下被拒绝)。
- -允许出现在字符串的开头以指示其符号。(在实际代码中,它们"看起来像"文字的一部分,但实际上是独立的一元运算符。)然而,该标志只能出现一次,并且后面不能跟空格。
- Infinity 和 -Infinity 被当作是字面量。在实际代码中,它们是全局变量。空字符串或仅包含空格的字符串转换为 0。不允许使用数字分隔符。
-
-
对象首先通过按顺序调用它们的
[@@toPrimitive]()
(使用"number"
提示)、valueOf()
和toString()
方法将其转换为原始值。然后将得到的原始值转换为数字。
4.String强转规则
- 字符串按原样返回。
- undefined 转换成 "undefined"。
- null 转换成 "null"。
- true 转换成 "true";false 转换成 "false"。
- 使用与 toString(10) 相同的算法转换数字。
- 使用与 toString(10) 相同的算法转换 BigInt。
- Symbol 抛出 TypeError。
- 对于对象,首先,通过依次调用其 @@toPrimitive(hint 为 "string")、toString() 和 valueOf() 方法将其转换为原始值。然后将生成的原始值转换为一个字符串。
5.强制类型转换遵循的规则总结
- 强制原始值转换:如果值已经是原始值,则此操作不会进行任何转换。
- 对象的强转:对象将依次调用它的
[@@toPrimitive]()
(将default
作为 hint 值)、valueOf()
和toString()
方法,将其转换为原始值。 - 强制数字类型转换、强制 number 类型转换、强制 BigInt 类型转换:
[@@toPrimitive]("number")
→valueOf()
→toString()
- 强制字符串类型转换:
[@@toPrimitive]("string")
→toString()
→valueOf()
在所有情况下,++[@@toPrimitive]()
如果存在,必须可调用并返回原始值++ ,否则报错TypeError
。
6.Object.is
Object.is()
确定两个值是否为相同值。如果以下其中一项成立,则两个值相同: