平常我们都是不建议在代码上编写一些比较难理解的代码,例如 x == y
和 'A' > 'B'
。这篇文章或许不能给你带来什么大的帮助,但是却可以让你了解一些你可能没接触到的知识点。
由于有些参考资料来源于 ECMA 规范,所以感兴趣的可能需要先看《读懂 ECMAScript 规格》这篇文章,当然也可以忽略。
类型之间的转换表
首先我们需要先了解基本的类型转换规则。
粗体需要特别留意的,可能跟你想象中的不一样。
原始值 | 转换为数字 | 转换为字符串 | 转换为布尔值 |
---|---|---|---|
false | 0 | “false” | false |
true | 1 | “true” | true |
0 | 0 | “0” | false |
1 | 1 | “1” | true |
“0” | 0 | “0” | true |
“000” | 0 | “000” | true |
“1” | 1 | “1” | true |
NaN | NaN | “NaN” | false |
Infinity | Infinity | “Infinity” | true |
-Infinity | -Infinity | “-Infinity” | true |
“” | 0 | “” | false |
“20” | 20 | “20” | true |
“Runoob” | NaN | “Runoob” | true |
[] | 0 | “” | true |
[20] | 20 | “20” | true |
[10,20] | NaN | “10,20” | true |
[“Runoob”] | NaN | “Runoob” | true |
[“Runoob”,”Google”] | NaN | “Runoob,Google” | true |
function(){} | NaN | “function(){}” | true |
{} | NaN | “[object Object]” | true |
null | 0 | “null” | false |
undefined | NaN | “undefined” | false |
这里根据上面的表格列举些例子:
-
数字转字符串
这个最常用了,这个也很好理解。
String(123)
或者
const a = 123; a.toString();
-
将字符串转换为数字
Number("3.14") // 返回 3.14 Number(" ") // 返回 0 Number("") // 返回 0 Number("99 88") // 返回 NaN
-
字符串转布尔值
Boolean('test') // 返回 true Boolean('0') // 返回 false Boolean('000') // 返回 true
== 比较运算符
规则来源于 ECMA 相关规范 Abstract Equality Comparison。
==
等同运算符的两边的类型不一样的时候,会有类型自动转换规则。
相同的类型可以直接比较(相当于 ===
比较),无需自动转换,不同类型 有下面几种自动转换规则(x == y
),规则优先级自上而下:
-
如果 x 是 null,y 是 undefined,返回 true
null == undefined
-
如果 x 是 undefined,y 是 null,返回 true
undefined == null
-
如果 x 是 Number,y 是 String,将 y 转化成 Number,然后再比较
0 == '0' // true 0 == '1' // false
-
如果 x 是 String,y 是 Number,将 x 转化成 Number,然后再比较
'0' == 0 // true '1' == 0 // false
-
如果 x 是 Boolean,那么将 x 转化成 Number,然后再比较
true == 0 // false true == 1 // true true == 2 // false true == 'test' // false false == 0 // true false == 1 // false false == 2 // false false == 'test' // false
-
如果 y 是 Boolean,那么将 y 转化成 Number,然后再比较
0 == true // false 1 == true // true 2 == true // false 'test' == true // false 0 == false // true 1 == false // false 2 == false // false 'test' == false // false
-
如果 x 是 String 或者 Number,y 是 Object,那么将 y 转化成基本类型,再进行比较
const a = {} 1 == a // false '1' == a // false true == a // false
-
如果 x 是 Object,y 是 String 或者 Number,将 x 转化成基本类型,再进行比较
const a = {} a == 1 // false a == '1' // false a == true // false
-
其他情况均返回 false
const a = {} a == null a == undefined 0 == null '2' == null false === null
即使我们搞懂了 ==
的规则,还是建议使用 ===
这种严格的运算符来替代 ==
。
> 或者 < 比较运算符
规则来源于 ECMA 相关规范 Abstract Relational Comparison。
x < y
的规则步骤如下(规则优先级自上而下):
-
x 和 y 需要转换为原始数据类型(ToPrimitive)
var px = ToPrimitive(x) var py = ToPrimitive(y) // 下面会沿用这两个变量的
除开原始的数据类型 undefined、null、boolean、number、string、symbol,其他的都属于对象,所以可以理解为这个 ToPrimitive 只对对象有作用。(还有个特殊的 NaN,不需要转换,NaN 可以理解为一种特殊的 number,typeof NaN === ‘number’)。
如果 x 或者 y 是对象,需要做转换处理,由于这里涉及的比较深,这里还是简单的说一下,知道有这回事就好。
var a = {} a < 'f' // true a < 'F' // false // a 会转变为 [object Object] // 相当于运行了 a.valueOf().toString()
为什么不直接 a.toString() 呢,看下下面的例子你就懂了(会首先运行 valueOf,如果返回的是对象则再运行 toString,否则直接返回 valueOf 的返回值)
var d = new Date(1572594637602) d < 1572594637603 // true d < 1572594637601 // false // d 会转变为 1572594637602 (当前时间转变的成的毫秒时间戳) // 相当于运行了 a.valueOf()
如果重写了 valueOf 方法,那么预期结果就不一样了
var d = {} // 这里重写定义了 valueOf d.valueOf = () => 1 d < 2 // true d < 0 // false // d 会转变为 1 // 相当于运行了 a.valueOf()
-
如果 px 和 py 都是字符串
-
如果 py 是 px 的前缀,返回 false
'test' < 'te'
-
如果 px 是 py 的前缀,返回 true
'test' < 'test1'
-
如果 px 不是 py 的前缀,而且 py 也不是 px 的前缀
那么需要从 px 和 py 的最小索引(假设是 k)对应的 字符的 UTF-16 代码单元值 进行对比。
假设 m = px.charCodeAt(k),n = py.charCodeAt(k),那么如果 m < n,返回 true,否则返回 false。
'A' < 'B' // true // 相当于 'A'.charCodeAt(0) < 'B'.charCodeAt(0)
更加复杂点的例子
'ABC' < 'ABD' // true // 相当于 // var a = 'ABC'.charCodeAt(0) < 'ABD'.charCodeAt(0) // false // var b = 'ABC'.charCodeAt(1) < 'ABD'.charCodeAt(1) // false // var c = 'ABC'.charCodeAt(2) < 'ABD'.charCodeAt(2) // true // a || b || c
-
-
其他情况 px 和 py 一律转为数字类型进行比较
var nx = Number(px) var ny = Number(py)
例子
'2' < 3 // true '2' < 1 // false var a = {} a < 1 // false,相当于,Number(a) < 1 a < 'a' // true,相当于 '[object Object]' < 'a' a < '[' // false,相当于 '[object Object]' < '[' var b = function(){} b < 'g' // true,相当于 'function(){}' < 'g' b < 'e' // false,相当于 'function(){}' < 'e'
x > y
的道理一样,这里就不多说了。
参考文章
- 读懂 ECMAScript 规格
- JavaScript 中 == 等同运算符的类型转换
- JavaScript 类型转换