前言
let a = 123
console.log(a)
console.log(1 == '1')
console.log(1 === '1')
我们知道 = 是赋值,右边赋给左边,而 == 和 === 都是判断左右两边是否相等的运算符,但是它们又有什么差别呢?我们输出上面结果试试
诶,为啥 == 返回的是 true , === 返回而是 false ,按照我们之前所理解的,都应该返回 false 才对,怎么不同类型的放一起比较还返回 true 呢?那是因为 == 在判断值的过程中会发生隐式类型转换,把左右两边转换成同种类型进行比较,而 === 不进行类型转换,只有当类型相同值也相同时才会返回 true 。什么是类型转换呢?今天带大家一探究竟
类型转换
无论是显式转换还是隐式转换都存在 原始 -> 原始, 引用 -> 原始
一、显式类型转换
顾名思义,你写的代码里“明明白白”地调用了某种转换手段,一看就知道“这里要把某值变成某类型”。我们用:Number / String / Boolean。这三个函数就是 JS 暴露给我们的“遥控器”:
| 遥控器 | 官方对应算法 | 一句话记忆 |
|---|---|---|
Number(x) | ToNumber(x) | 把 x 榨成数字 |
String(x) | ToString(x) | 把 x 榨成字符串 |
Boolean(x) | ToBoolean(x) | 把 x 榨成布尔 |
注意: ToNumber/ToString/ToBoolean 是 ECMAScript 规范里的抽象操作,代码里写不出来,但所有隐式转换最终都会调到它们。
let num = -1
let str = 'hello'
let flag = true
console.log(String(num));
console.log(String(flag));
console.log(Number(str));
console.log(Number(flag));
console.log(Boolean(num));
console.log(Boolean(str));
这里面的 NAN 是 not a number 的意思,true 则是代表 1 ,false 则是代表 0。
二、隐式类型转换
引用类型转原始值(v8自发的执行)通常发生在隐式转换过程中
- 转布尔 --- 所有的引用类型转布尔都是 true
- 转数字
- Number(x)
- ToNumber(ToPrimitive(x, Number))
- ToPrimitive:
- 调用 valueOf() 方法,如果得到原始值,则返回
- 否则,调用 toString() 方法,如果得到原始值,则返回
- 否则,报错
- 转字符串
- String(x)
- ToString(ToPrimitive(x, String))
- ToPrimitive:
- 调用 toString() 方法,如果得到原始值,则返回
- 否则,调用 valueOf() 方法,如果得到原始值,则返回
- 否则,报错
valueOf()
valueOf() 只能将包装类变成原始类型,比如 new 调用得到的实例对象
let a = new Number(123)
console.log(a.valueOf())
let b = new Boolean(234)
console.log(b.valueOf())
let c = new String('hello')
console.log(c.valueOf())
toString()
{}.toString()// '[object Object]'[].toString()// 返回由数组内部元素以逗号拼接的字符串其他.toString()// 将值用引号引起来
什么情况下会发生隐式类型转换
- 四则运算
+ - * / %默认往Number上转 - 判断语句
if while == >= <= > < !=
注意: +
- 作为一元运算符 会直接调用 ToNumber(x) (Number('123') === +('123'))
- 作为二元运算符
val1 + val2
lprim = ToPrimitive(val1) rprim = ToPrimitive(val2)
lprim + rprim - 如果 lprim 或者 rprim 有一个是字符串,另一个直接被 ToString()
- 否则 全部 ToNumber
结尾彩蛋
[] == ![] // true
// [] == !true
// [] == false
// [] == 0
// '' == 0
// 0 == 0
{} + [] ==>在Windows中被当成代码块+数组,于是只剩 +[] → 0 (经典面试坑)(node不一样)
[] + {} ==>等价于 "" + "[object Object]" → "[object Object]"
结语
今天我们沿着 1 == '1' 这条裂缝,一路撬开了 JS 的“类型转换黑盒”:
===是严格的“同类型+同值”守门员; == 则是会隐式施法的“类型橡皮擦”。- 显式转换
Number() / String() / Boolean()让你对结果一目了然;隐式转换ToPrimitive则在运算符背后悄悄调用valueOf → toString双通道。 - 二元
+只要遇到字符串就立刻化身“拼接怪”;而{} + []的零结果,只是解析器把{}当成代码块的小彩蛋。
记住口诀:
“业务写代码用 ===,面试刷题防隐式;对象先 valueOf 再 toString,括号一加魔法失效。”
下次再看到 [] == ![] 返回 true ,你就能笑着把转换路径一步步剥给对方听——真正的“魔法”,不过是规范里写好的算法罢了。