JS 数据类型转换

类型转换可以分为两种:隐式类型转换显式类型转换

显式:比如 Number(value) String(value) …

隐式:对不同类型的值使用运算符时,值可以自动转换,比如 1 == null

我们需要知道:在 JS 中只有3中类型的转换:转换为 Number,String,Boolean类型

所以我们只需要弄清楚在什么场景下应该转成哪种类型就可以了

转换为boolean

显式Boolean()方法可以直接用来将值转换成布尔型

Boolean(2) // true

隐式:通常在逻辑判断或者有逻辑运算符时被触发

if(2) {} // 逻辑判断
!!2 // 逻辑运算
2 || 'hello' // 逻辑运算

let x = 'hello' && 123 // x === 123
// 逻辑运算符(比如 || 和 &&)是在内部做了 boolean 类型转换,但实际上返回的是原始操作数的值

boolean类型转换只有 true,false两种结果。

除了 0、NaN、空字符串、null、undefined五个值是false,其余都是true

额外补充:

逻辑或 ||:一真为真,a || b,只要a为真就返回a的执行结果,b不执行;a为假则执行b,并返回b执行后的结果

逻辑与 &&:一假为假,a && b,只要a为假就返回a的执行结果,b不执行;a为真则执行b,并返回b执行后的结果

转换为为string

  • 显式:String()方法可以用来显式将值转为字符串。
String([1,2,3]) // "1,2,3"
String({}) // '[object Object]'
String(true) // 'true'
  • 隐式:隐式转换通常在有 + 运算符并且只是至少有一个操作数是 string 类型时被触发,即字符串拼接
1 + '123'  //"1123" 
1 + {} // '1[object Object]'
'1' + null // '1null'
  • 把引用类型转换为String时就会调用Object.prototype.toString(), 输出的格式是[object 对象的类型]

  • null 与字符串拼接时null直接转为 ‘null’ (内部的实现)

转换为number

显式Number()方法可以用来显式将值转换成数字类型

  • 字符串转换为数字:空字符串变为0,如果出现任何一个非有效数字字符,结果都是NaN
Number("")           //0
Number("10px") //NaN
Number("10") //10
  • 布尔转换为数字
Number(true) // 1
Number(false) // 0
  • null 和 undefined 转换成数字
Number(null) // 0
Number(undefined) // NaN
  • Symbol无法转换为数字
Number(Symbol()) // Cannot convert a Symbol value to a number
  • BigInt
Number(BigInt(10)) // 10
Number(10n) // 10

BigInt 是一种内置对象,它提供了一种方法来表示大于 2^53 - 1 的整数。BigInt 可以表示任意大的整数。

可以用在一个整数字面量后面加 n 的方式定义一个 BigInt ,如:10n,或者调用函数 BigInt()(但不包含 new 运算符)并传递一个整数值或字符串值,如BigInt(10)

  • 对象转换为数字,会按照下面的步骤执行
  1. 先调用对象的 Symbol.toPrimitive 这个方法,如果不存在这个方法

    MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive

  2. 再调用对象的 valueOf() 获取原始值,如果获取的值依然不是数字

    valueOf() 方法返回指定对象的原始值。

  3. 再调用对象的 toString() 把其变为字符串

    把引用类型转换为String时就会调用Object.prototype.toString(), 输出的格式是[object 对象的类型]

  4. 最后再把字符串基于Number()方法转换为数字

let obj = {
name:'xxx'
}
console.log(obj-10) // 数学运算:先把obj隐式转换为数字,再进行运算
//运行机制
obj[Symbol.toPrimitive] //undifined
obj.valueof() // {name:xxx}
obj.toString() // '[object Object]'
Number ("[object object]") // NaN
NaN-10 // NaN

隐式

number 的隐式类型转换是比较复杂的,因为它可以在下面多种情况下被触发

  • 比较操作(>, <, <=, >=)

  • 按位操作(| & ^ ~)

  • 算数操作(- + * / %),

    注意:当 +存在任意的操作数是 string 类型时,转换到string类型为止,不会触发 number 类型的隐式转换

  • 一元 + 操作

    一元就是只有一个操作数,+5 +[]

    +[] --> 0 相当于Number([])

    +{} --> NaN 相当于String({})=‘[object,Object]’;Number(‘[object,Object]’) -->NaN

需要注意的情况

javascript中加法会触发3种类型转换,即将值转换为原始值,转换为字符串,转换为数字。这刚好对应了javascript引擎内部的转换操作:ToPrimitive(),toString(),toNumber()

{} + [] === 0 // true
[] + {} === 0 // false

// {} + [],对于编译器来说,{}在开头,被解析成代码块,不会返回任何值
// 所以{} + []实际上就是 +[]
// []通过ToPrimitive(),toString() 变成 ""
// 最后 toNumber() --> 0

[] + {} // 这里{}就是一个对象
// String([])='' String({})='[object Object]'
// 有string类型不会触发number转换了,两边都是string直接拼接
// 所以 '' + '[object Object]' --> '[object Object]'

操作符 == 两边的隐式转换

如果两边的数据类型不同,需要先转为相同类型再进行比较

  • 对象 == 字符串
[1,2,3] == '1,2,3'  // true
// 转为字符串
// [1,2,3].toString() --> '1,2,3'

{name:'helo'} == "{name:'helo'}" // false
// {name:'helo'}.valueOf().toString() --> '[object Object]'
  • null/ undefined
null == undefined // true
null === undefined // false
//null/undefined和其他任何值都不相等
  • 对象 == 对象
{} == {} // false 比较的是堆内存地址,地址相同才相等
  • NaN
NaN == xxx  都是false

除了以上的四种情况,只要两边类型不一致,都是转换为数字再进行比较

最后,看题:

let result = 100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false
image.png

参考资料:

https://juejin.cn/post/6956170676327677966

数据类型的判断

https://juejin.cn/post/7061588533214969892#heading-29

把引用类型转换为String时就会调用Object.prototype.toString(), 输出的格式是[object 对象的类型]

Object.prototype.toString.call() 有显式绑定,

因此 Object.prototype.toString.call(xxx)就是 找到xxx中的toString方法,输出的对象的类型就是根据xxx来的

神奇的加法

https://blog.csdn.net/dk2290/article/details/86534595