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() 确定两个值是否为相同值。如果以下其中一项成立,则两个值相同: