js隐式类型转换详解,看这篇文章就够了!

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)由引擎调用,那什么时候hintnumberstringdefault

const object1 = {
  [Symbol.toPrimitive](hint) {
      console.log(hint)
  },
};
// 当执行 +object1    hint = number
// 当执行 `${obj2}`   hint = string
// 其余情况 hint=default

:::

2.隐式转换示例

console.log({} + []); // "[object Object]"

{}[] 都没有 [@@toPrimitive]() 方法。因此会调用valueOf方法,而valuieOf返回对象自身,由于返回值还是对象,因此继续调用toString方法,{}.toString()返回"[object Object]"[].toString()返回是空字符串

{} + {} 
//NAN
({} + {})
'[object Object][object Object]'

第一次看到这个结果我懵了,想不到原因,最后查看资料,发现JavaScript 把第一个 {} 解释成了一个空的代码块(code block)并忽略了它。 NaN 其实是表达式 +{} 计算的结果 (+ 加号以及第二个 {})。 你在这里看到的 + 加号并不是运算符「加法」,而是一个一元运算符,作用是将它后面的操作数转换成数字,和 Number() 函数完全一样。为什么第一个 {} 会被解析成代码块(code block)呢? 因为整个输入被解析成了一个语句:如果左大括号出现在一条语句的开头,则这个左大括号会被解析成一个代码块的开始。

{} + []
0
/*转换流程如下
+[]
[].valueOf()//不是原始值
[].toString()
Number([].toString())  
Number("")
0
*/
[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。不允许使用数字分隔符。
  • Symbol 抛出 TypeError

  • 对象首先通过按顺序调用它们的 [@@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() 确定两个值是否为相同值。如果以下其中一项成立,则两个值相同:

  • 都是 undefined
  • 都是 null
  • 都是 true 或者都是 false
  • 都是长度相同、字符相同、顺序相同的字符串
  • 都是相同的对象(意味着两个值都引用了内存中的同一对象)
  • 都是 BigInt 且具有相同的数值
  • 都是 symbol 且引用相同的 symbol 值
  • 都是数字且
    • 都是 +0
    • 都是 -0
    • 都是 NaN
    • 都有相同的值,非零且都不是 NaN

你可能感兴趣的:(javascript,开发语言,ecmascript)