JS数据类型转换规则 (一)

avatar
前端工程师 @豌豆公主

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情

JS数据类型转换规则(一)

引言

  • 在我们平常工作中,经常会听到这样的diss, 你怎么还用 === ,多写个== 能()啊。但是当你看一个库的实现,又会使用 ==,比如同时判断 null,undefined。再比如 你需要将一个数字转为为字符串,或者将字符串转为数字,会使用 + '', *1,这些小技巧。再比如要获取当前时间戳,你不想使用new Date().getTime, 直接使用+new Date()也可以得到相同的结果。这些小的知识点,都和js的类型转化有关。下面就让我们一起学习js中的类型转换规则

其他数据类型转换为Number

  • 数据转换分隐式转换,和显式转换。隐式转换一般是浏览器去使用Number(val) 默认做转换。显示转换 也可以使用 parseInt,parseFloat,当然如果你显示使用Numebr(),也是可以的

隐式转换(Nunber)

  • 数字运算(-,*)
8 - '2' = 6
实际上浏览器会使用Number先将‘2’,进行隐式转换 Number('2') // 2

'12' * 1 = 12 (常用于字符串转数字)

  • isNaN检测(检测是不是不是有效数字)
isNaN('1') // false
实际上浏览器会使用Number先将'1',进行隐式转换 Number('1') // 1
  • == 比较
1 == true
实际上浏览器会使用Number先将true,进行隐式转换 Number(true) // 1

隐式转换规则

  1. 字符串 转换为 数字: 空串变为0,如果出现任何非有效数字的字符,结果都是NaN
  • 空串变为0
8 - '' = 8 等价于 8 - 0 =  8
因为 Number('') = 0
  • 非有效字符结果都是NaN
8 - '12px' = NaN

因为 Number('12rpx') // NaN
  1. 布尔值转换为数字: true -> 1 ; false -> 0
  • true -> 1
4- true = 3 
因为 Number(true) // 1
  • false -> 0
5 - false = 5
因为 Number(false)// 0
  1. null -> 0 ; undefined -> NaN
5 - null = 5
因为 Number(null) // 0
5 - undefined = 5
因为 Number(undefined) // NaN
  1. Symbol 无法转换为数字,会报错

image.png 5. BigInt 去除“n”, 超过最大安全数,会不准确

Number(10n) 10

image.png 6. 对象转换为数字(重点)

    1. 先调用对象的Symbol.toPrimitive这个方法,如果不存在这个方法
    1. 再调用对象的valueof获取原始值,如果获取的值不是原始值
    1. 再调用对象的toString, 把其变为字符串
    1. 最后再把字符串基于Number 转换为数字

demo1: 获取时间戳

  • 标准获取方式

image.png 利用类型转换获取

image.png 利用类型转换获取(流程介绍)

  • 首先检测[Symbol.toPrimitive] 有没有,如果有,并且是个函数,则调用
let timer = new Date()

timer[Symbol.toPrimitive]('number') // 1661672839917

这个结果和Number(timer是一样的)

转换完毕

demo2: 将数组转换为数字

5 - [3] = 2

  • 首先检测[Symbol.toPrimitive] 有没有,如果有,并且是个函数,则调用

image.png 数组没有这个方法,那么接着走下面的判断

  • 调用对象的valueof获取原始值

image.png

获取的值不是原始值,那么接着判断

  • 调用对象的toString, 把其变为字符串

image.png

  • 最后再把字符串基于Number 转换为数字

image.png

结果:5 - [3] = 2。因为数组经过一系列的隐式转换,变为了数字3。 如果数组个数大于1 ,看看会出现什么情况

image.png 因为转换为字符串时,出现了非有效数字的字符,,所以结果是NaN

显示转换

parseInt()

  • parseInt(stringradix)  解析一个字符串并返回指定基数的十进制整数,radix 是 2-36 之间的整数,表示被解析字符串的基数。(如果不写,或者是0,默认是10。有效范围是2-36,不在这个区间,则返回NaN)
parseInt('123', 5) // 将'123'看作 5 进制数,返回十进制数 38 
=> 1*5^2 + 2*5^1 + 3*5^0 = 38

parseInt('12px', 10) // 12

parseInt('12.9px', 10) // 12

parseInt('12px') // 12

parseInt('12px', 0) // 12

parseInt('12d', 37) // NaN

parseInt('d12px', 10) // NaN

parseInt(null) // NaN

parseInt(undefined) // NaN

parseFloat()

parseFloat()  函数解析一个参数(必要时先转换为字符串)并返回一个浮点数。如果给定值不能被转换成数值,则会返回 NaN


parseFloat('12.9') // 12.9

parseFloat('12.9px') // 12.9

parseFloat('12.9px') // 12.9

parseFloat('12.9px') // 12.9

parseFloat('12.9d') // NaN

parseFloat('d12px') // NaN

demo练习

let arr = [27.2, 0, '0013', '14px', '123']
arr = arr.map(parseInt)

image.png

我们具体剖析一下

  • map
arr = arr.map((item, index) => {
    return item * index
})

如果将parseInt 作为参数传入,相当于如下代码

image.png

根据参数要求: 如果参数不是一个字符串,则将其转换为字符串 (使用 ToString抽象操作) 所以参数都会先被转成字符串

  1. parseInt(27.2, 10): radix如果不写,或者是0,默认是10。 所以 parseInt('27.2', 10) 是整数27

  2. parseInt(0, 1): radix的范围是 2 -36(特殊情况除外), 1 不在范围内,所以 结果是NaN

  3. parseInt('0013', 2): radix是2进制, 所以相当于把parseInt('001', 2)准换为十进制 => 0✖️2^2 + 0✖️2^1 + 1✖️2^0 = 1

  4. parseInt('14px', 3): radix是3进制, 所以相当于把parseInt('1', 3)准换为十进制 => 1✖️3^0 = 1

  5. parseInt('123', 4): radix是4进制, 所以相当于把parseInt('123', 4)准换为十进制 => 1✖️4^2 + 2✖️4^1 + 3✖️4^0 = 27

总结

  • 隐式转换: 字符串,布尔,null,undefined 基本数据类型转数字,步骤很简单。但是对象转数字,却要经过很多步骤,比如要经过Symbol.toPrimitive,valueOf,toString()
  • 显示转换,最主要的用途就是我们只取数字部分,当然取整数和浮点数,区别开方法即可。最重要的还有他的第二个参数radix要掌握好
  • 下一篇聊一聊其他数据类型的转换规则