你真的理解了比较运算符吗?

平常我们都是不建议在代码上编写一些比较难理解的代码,例如 x == y'A' > 'B'。这篇文章或许不能给你带来什么大的帮助,但是却可以让你了解一些你可能没接触到的知识点。

由于有些参考资料来源于 ECMA 规范,所以感兴趣的可能需要先看《读懂 ECMAScript 规格》这篇文章,当然也可以忽略。

类型之间的转换表

首先我们需要先了解基本的类型转换规则。

粗体需要特别留意的,可能跟你想象中的不一样。

原始值转换为数字转换为字符串转换为布尔值
false0"false"false
true1"true"true
00"0"false
11"1"true
"0"0"0"true
"000"0"000"true
"1"1"1"true
NaNNaN"NaN"false
InfinityInfinity"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
null0"null"false
undefinedNaN"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),规则优先级自上而下:

  1. 如果 x 是 null,y 是 undefined,返回 true

    null == undefined
  2. 如果 x 是 undefined,y 是 null,返回 true

    undefined == null
  3. 如果 x 是 Number,y 是 String,将 y 转化成 Number,然后再比较

    0 == '0' // true
    0 == '1' // false
  4. 如果 x 是 String,y 是 Number,将 x 转化成 Number,然后再比较

    '0' == 0 // true
    '1' == 0 // false
  5. 如果 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
  6. 如果 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
  7. 如果 x 是 String 或者 Number,y 是 Object,那么将 y 转化成基本类型,再进行比较

    const a = {}
    1 == a    // false
    '1' == a  // false
    true == a // false
  8. 如果 x 是 Object,y 是 String 或者 Number,将x转化成基本类型,再进行比较

    const a = {}
    a == 1    // false
    a == '1'  // false
    a == true // false
  9. 其他情况均返回 false

    const a = {}
    a == null
    a == undefined
    0 == null
    '2' == null
    false  === null

即使我们搞懂了 ==的规则,还是建议使用 ===这种严格的运算符来替代 ==

> 或者 < 比较运算符

规则来源于 ECMA 相关规范 Abstract Relational Comparison

x < y的规则步骤如下(规则优先级自上而下):

  1. 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()
  2. 如果 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
  3. 其他情况 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的道理一样,这里就不多说了。

参考文章

原文链接:segmentfault.com

上一篇:基于SEER的区块链版赛亚麻将游戏Pre alpha版本内测啦!
下一篇:带你走进web医疗影像的世界

相关推荐

  • (转载)如何通俗易懂的理解Redux

    作者:Wang Namelos 链接:https://www.zhihu.com/questio...(https://www.zhihu.com/question/41312576/answer/9...

    2 年前
  • 面试:彻底理解Cookie以及Cookie安全

    Cookie是什么 Cookie是服务端发送到用户浏览器并且保存到本地的一小块数据,它会在浏览器下次向同一服务器发起请求时,被携带到服务器上。 它的作用: 经常用来做一些用户会话状态管理、个性化设...

    2 个月前
  • 面试官:聊聊对Vue.js框架的理解

    前言 今年OKR定了一条KR是每一个季度进行一次前端相关技术的分享,还有十几天就到2020年了,一直忙于业务开发,没有时间准备和学习高端话题,迫于无奈,那就讲讲平时使用频率较高,却没有真正认真的了解其...

    5 个月前
  • 面试官: 说说你对async的理解

    大家好,我是小雨小雨,致力于分享有趣的、实用的技术文章。 内容分为翻译和原创,如果有问题,欢迎随时评论或私信,希望和大家一起进步。 分享不易,希望能够得到大家的支持和关注。

    2 个月前
  • 面向对象的程序设计——理解对象

    面向对象的程序设计 ECMA262 把对象定义为:无须属性的集合,其属性可以包含基本值、对象或者函数。 理解对象 属性类型 ECMAScript 中有两种属性:数据属性和访问器属性,...

    2 年前
  • 零代码深入浅出React并发模式,带你理解React Fiber架构

    React Fiber架构有一定的复杂度,如果硬着头皮去啃源码,我们会深陷于庞大的代码量和实现细节之中,往往学不到什么东西。 React并发模式是ReactFiber架构的重要应用,本文不贴任何Rea...

    4 个月前
  • 闭包的简单理解

    主要分三部分说: 一、什么是闭包?二、闭包有什么好处?应用在哪里? 1、什么是闭包 第一个特点:可以是函数嵌套函数 第二个特点:内部函数可以引用外部函数的参数和变量 b变量都要被内部...

    2 年前
  • 重新理解闭包,扒出来一个伪闭包?

    七、 问题又来了 按照最先前的说法,函数内部的函数必须被函数外部的一个变量给绑定了,这个函数才不会被垃圾回收机制给释放掉。 那这个闭包内部的函数到底被外部的那个变量给绑架了呢? ...

    2 年前
  • 重新理解async和await

    async 和 await 在干什么 任意一个名称都是有意义的,先从字面意思来理解。async 是“异步”的简写,而 await 可以认为是 async wait 的简写。

    9 个月前
  • 重学前端学习笔记(二十八)--通过四则运算的解释器快速理解编译原理

    笔记说明 重学前端是程劭非(winter)【前手机淘宝前端负责人】在极客时间开的一个专栏,每天10分钟,重构你的前端知识体系(https://time.geekbang.org/column/i...

    1 年前

官方社区

扫码加入 JavaScript 社区