由[] == ![]谈一谈JS中的数据类型转换和规则

191 阅读4分钟

JS中的转换类型有哪些?

(1)转换为字符串

  • toString([radix]):调用自身的toString方法,返回对应字符串表示

    ps:Number类型的toString方法存在两种模式:普通模式和基模式

    其中基模式中可以传入radix,radix为2-36范围内的数字,表示要输出格式的几进制。

    规则:

    • Number:返回数字对应的字符串表示

    • Boolean:true -> "true" false -> "false"

    • Array:返回实际内容的连接(包含分隔的逗号) var arr = [1, 2, 3, 4]; console.log(arr.toString()) // "1,2,3,4"

    • String:返回对应的值

    • Function:返回函数结构体

    • Object:返回"[object Object]"

  • String(thing):将任意的数据类型转换成字符串表示

    规则:

    • 如果传入的数据类型有toString方法,则调用toString方法,并返回字符串表示

    • 如果没有toString方法,则返回相对应的字符串。

      e.x. null --> "null" undefined --> "undefined"


(2)转换为数字

  • Number(x):将任意类型的值转换成数值类型。

    规则:

    • 布尔类型:true -> 1, false -> 0

    • 字符串类型

      1. 如果为空字符串,则转换为0

      2. 如果字符串中包含数字和小数点以外的字符,则转换为NaN

    • undefined:转换为NaN

    • null:转换为0

    • 引用类型:先调用toPrimitive(),再调用valueOf(),最后调用toString()(每一步调用完毕,都按照上述1、2、3规则进行判断,如果不符合再调用其他的方法)

  • parseInt(radix)

    • parseInt可以传入指定的进制基数

    • 规则

      1. 如果第一个非空字符不是数字、正负号或者0x(16进制表示的数字),则返回NaN
      2. 满足第一点时,按顺序向后解析,直到遇到第一个不为数字的字符返回
      3. 对第二步返回的结果用对应的radix进行解析
  • parseFloat(radix)

    • 规则基本与parseInt一致,额外添加对小数点的校验

(3)转换为布尔类型

规则:

空字符串、NaN、Undefined、Null、false、0会转换为false

其他会转换为true


(4)引用类型转换为原始类型

  • 转换为字符串类型

    • 如果引用类型存在[Symbol.toPrimitive]方法,则调用该方法

    • 如果该方法返回值不为字符串类型,则调用toString()方法

    • 如果toString方法返回值不是字符串类型,则继续调用valueOf方法

    按照上述优先级和执行顺序进行转换

  • 转换为数值类型

    • 将上述转换为字符串类型步骤中的toSting()和valueOf()进行调换下顺序即可

隐式转换

上面我们简单了解了JS中存在的类型转换,那么接下来我们聊一聊在js的执行过程中常见的一些隐式类型转换。

在将某些类型隐式转换为数值类型的时候,默认调用的是Number()

在将某些类型隐式转换为字符串类型的时候,默认调用的是toString()

(1)非严格等于运算符 ==

在非严格等于运算中,如果运算符左右两侧类型不一致,js会先对其进行隐式的类型转换,然后再对值进行比较。

规则:

  • 引用类型 == 引用类型:根据引用类型指向的内存地址是否相同来判断
  • 对象 == 数字:将对象转换为数字后再进行比较
  • 对象 == 布尔:将对象和布尔都转换为数字后再进行比较
  • 对象 == 字符串:把对象和字符串都转换为数字后再进行比较
  • 字符串 == 数字:把字符串转换为数字后进行比较
  • 字符串 == 布尔:把字符串和布尔都转换为数字后再进行比较
  • 布尔 == 数字:把布尔转换为数字进行比较

由上可以看出,当两侧类型不相同时,基本上都会先将其中一个或者两个转换为数字类型之后再进行值的比较。

另外,还有几个特殊的类型比较:

  • null == undefined // true
  • null == NaN // false
  • null == null // true
  • undefined == undefined // true
  • undefined == NaN // false
  • NaN == NaN // false

(2)加号运算符 +

  • 字符串 + 基本类型:

将其他基本类型隐式转换为字符串(调用toString)后再进行相应计算,此时+相当于字符串连接符

  • 数字 + 基本类型

将基本类型转换为数值类型后再进行加法运算,如果能正常计算则返回计算结果。否则返回NaN

  • 数字 + 引用类型

将引用类型按照引用类型的转换规则,转换成Number类型,然后进行计算

(3)作为属性名称

将对应的变量类型转换为字符串后再进行赋值操作

常见的是将对象作为一个属性的名称,此时这个对象会转换为'[object Object]'


最后,我们回到题目中的[] == ![]这道题目

按照上述的非严格等于的隐式类型转换规则,我们应该将==两侧的表达式都转换成数字类型以后再进行相应的比较:

左侧:[] -> 0

右侧:![]本身是一个布尔类型([] -> true ![] -> false)false转换为数值类型-> 0

因此[] == ![] 的结果为true。