• Java Script 中 ==(Equal) 和 === (Identity Equal) 的区别和比较算法逻辑


    判断两个变量是否相等在任何编程语言中都是非常重要的功能。

    JavaScript 提供了 == 和 === 两种判断两个变量是否相等的运算符,但我们开始学习的时候 JavaScript 的时候,就被一遍又一遍的告知:

    • === 要求变量的类型和值均相等,才能返回true。
    • 使用 === 来避免因JavaScript 类型转换带来的问题。

    这样增加了 JavaScript 语法的灵活性但是也带来很多头疼的问题:

    • 使用 ==/!=是 ===/!== 来判断两个变量是否相等?
    • 为什么,JS 编码推荐使用 ===/!= 而不是 ==/!=,大部分的编程语言不都是使用==/!=么?

    为了要回答这个问题,让我们看一下 JavaScript 所遵守的标准 ECMAScript 对于==和 === 是怎么描述的吧!

    === 详解

    Identity Equal或 Strict Equal, 在 ECMAScript -- Java Script 所遵守的标准中,算法的定义为:The Strict Equality Comparison Algorithm, 规则如下:

    1. 如果 参数 x 的数据类型和 参数 y 的数据类型不一致,这返回 false
    2. 如果 参数 x 的数据类型为 undenfined, 则返回 true
    3. 如果 参数 x 的数据类型为 null, 则返回 true
    4. 如果 参数 x 的数据类型为 Number, 则:
      1. 如果 x 是  NaN 返回 false
      2. 如果 y 是  NaN 返回 false
      3. 如果 x 是 +0 并且 y 为 -0, 返回 true
      4. 如果 x 是 -0 并且 y 为 +0, 返回 true
      5. 如果 x 和 y 有着相同的数值,返回 true
      6. 返回 false
    5. 如果 x 的类型为 String, 且 x 与 y 有着相同的顺序排列的字符串, 返回 true
    6. 如果 x 的类型为 boolean, 且 x 与 y 拥有相同的布尔值,返回 true
    7. 如果 x 的类型为 Object, 且 x 与 y 指向相同的对象,返回 true

    伪代码:

     1 function strictEqual(x, y) {
     2     // If Type(x) is different from Type(y), return false.
     3     if (!valueEqual(typeof (x), typeof (y))) {
     4         return false;
     5     }
     6 
     7     // If Type(x) is Undefined, return true.
     8     // If Type(x) is Null, return true.
     9     if (valueEqual(typeof (x), "undefined") || valueEqual(x, null)) {
    10         return true;
    11     }
    12 
    13 
    14     if (valueEqual(typeof (x), "number")) {
    15         // If x is NaN, return false.
    16         if (isNaN(x)) {
    17             return false;
    18         }
    19 
    20         // If y is NaN, return false.
    21         if (isNaN(y)) {
    22             return false;
    23         }
    24      
    25         // If x is +0 and y is −0, return true.
    26         if (valueEqual(x, +0) && valueEqual(y, -0)) {
    27             return true;
    28         }
    29 
    30         // If x is −0 and y is +0, return true.
    31         if (valueEqual(y, +0) && valueEqual(x, -0)) {
    32             return true;
    33         }
    34 
    35         // If x is the same Number value as y, return true.
    36         if (valueEqual(x, y)) {
    37             return true;
    38         }
    39 
    40         return false;
    41     }
    42 
    43     if (valueEqual(typeof (x), "string")) {
    44         // If Type(x) is String, then return true if x and y are exactly
    45         // the same sequence of characters 
    46         //   (same length and same characters in corresponding positions); otherwise, return false.
    47         return hasSameChar(x, y);
    48     }
    49 
    50     if (valueEqual(typeof (x), "boolean")) {
    51         return valueEqual(x, y);
    52     }
    53 
    54     if (valueEqual(typeof (x), "object")) {
    55         // Return true if x and y refer to the same object. Otherwise, return false.
    56         return hasSameReference(x, y);
    57     }
    58 
    59     return false;
    60 }
    View Code

    逻辑图:

    == 详解

    Equal, 在两个对比变量数据类型相同时, 和=== 有着一样的行为算法实现,但是当两个对比的变量数据类型不同时,ECMAScript/JavaScript 有着自定义的转换和比较逻辑:参考 The Abstract Equality Comparison Algorithm

      1. 如果 x 为 null, 且 y 为 undefined, 返回 true
      2. 如果 x 为 undefined, 且 y 为 null, 返回 true
      3. 如果 x 的数据类型为 Number, 且 y 的数据类型为 string, 则将 y 转换为 Number,然后进行比较
      4. 如果 x 的数据类型为 String, 且 y 的数据类型为 Number, 则将 x 转换为 Number,然后进行比较
      5. 如果 x 的数据类型为 Boolean, 将x 转换为数字类型,当 x 为 true 时转换为 1, 否则转换为 0 进行比较
      6. 如果 y 的数据类型为 Boolean, 将 y 转换为数字类型,当 y 为 true 时转换为 1, 否则转换为 0 进行比较
      7. 如果 x 的数据类型为 String 或者 Number, 且 y 为 Object, 则使用 valueOf 函数,将 y 转换为简单类型进行比较
      8. 如果 y 的数据类型为 String 或者 Number, 且 x 为 Object, 则使用 valueOf 函数,将 x 转换为简单类型进行比较
      9. 返回 false

       从上述定义不难总结出以下几点:

      1. 该算法为递归算法,转换后,继续调用其自身直到能比较且返回为止
      2. 该算法依赖于 Strict Equal 的实现
      3. 进行转换时,具体转换依赖于数据类型的定义的方法,如Number() 函数

      伪代码:

     1 function abstractEqual(x, y) {
     2 
     3     // if x and y has same type
     4     if (valueEqual(typeof (x), typeof (y))) {
     5         return strictEqual(x, y);
     6     }
     7 
     8     // If x is null and y is undefined, return true.
     9     if (valueEqual(x, null) && valueEqual(y, undefined)) {
    10         return true;
    11     }
    12 
    13     // If x is undefined and y is null, return true.
    14     if (valueEqual(x, undefined) && valueEqual(y, null)) {
    15         return true;
    16     }
    17 
    18     // Type(x) is Number and Type(y) is String,
    19     if (valueEqual(typeof (x), "number") && valueEqual(typeof (y), "string")) {
    20 
    21         var convertedY = Number(y);
    22 
    23         // return the result of the comparison x == ToNumber(y)
    24         return abstractEqual(x, convertedY);
    25     }
    26 
    27     // Type(x) is Number and Type(y) is String,
    28     if (valueEqual(typeof (x), "string") && valueEqual(typeof (y), "number")) {
    29 
    30         var convertedX = Number(x);
    31 
    32         // return the result of the comparison x == ToNumber(y)
    33         return abstractEqual(convertedX, y);
    34     }
    35 
    36     // Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
    37     if (valueEqual(typeof (x), "boolean")) {
    38         var convertedToIntX = Number(x);
    39 
    40         return abstractEqual(convertedToIntX, y);
    41     }
    42 
    43     // Type(x) is Boolean
    44     if (valueEqual(typeof (y), "boolean")) {
    45         var convertedToIntY = Number(y);
    46 
    47         // return the result of the comparison ToNumber(x) == y.
    48         return abstractEqual(x, convertedToIntY);
    49     }
    50 
    51     // If Type(x) is either String or Number and Type(y) is Object,
    52     if ((valueEqual(typeof (x), "string") || valueEqual(typeof (x), "number")) && valueEqual(typeof (y), "object")) {
    53         var toPrimitiveY = y.valueOf();
    54 
    55         // return the result of the comparison x == ToPrimitive(y).
    56         return abstractEqual(x, toPrimitiveY);
    57     }
    58 
    59 
    60     // If Type(x) is either String or Number and Type(y) is Object,
    61     if ((valueEqual(typeof (y), "string") || valueEqual(typeof (y), "number")) && valueEqual(typeof (x), "object")) {
    62         var toPrimitiveX = x.valueOf();
    63 
    64         // return the result of the comparison x == ToPrimitive(y).
    65         return abstractEqual(toPrimitiveX, y);
    66     }
    67 
    68     return false;
    69 }
    View Code

    逻辑图:

     

    附加上本例使用的判断相等的函数的代码,直接使用了 JavaScript 的 == 来实现,为了 demo 么!呵呵,这是一个很号的接口,实际上,我也实现不出来 :).

     1 function valueEqual(x, y) {
     2     return x === y;
     3 }
     4 
     5 function hasSameChar(x, y) {
     6     return x === y;
     7 }
     8 
     9 function hasSameReference(x, y) {
    10     return x === y;
    11 }
    View Code

    总结

    现在,我们已经知道 == 和 === 在判断两个变量是否相等时所使用的算法的基本实现。帮助我们理解一些 JavaScript 中判断相等时一些"诡异“ 的行为。

    把我们写的 Script 放在一个 HTML 文件里,用 Chrome 代开,按 F12, 开始我们的调试吧:

    测试 JS 代码 运行结果           JS 代码   运行结果 备注
    var x = 1, y = "1";console.log(strictEqual(x,y)); console.log(abstractEqual(x,y)) false, true var x = 1, y = "1";console.log(x === y); console.log(x == y) false,true == 时,y 先转换为数字类型1
    var x = 1, y = "not a number";console.log(strictEqual(x,y)); console.log(abstractEqual(x,y)) false, falase var x = 1, y = "not a number";console.log(x === y); console.log(x == y) false, false  y 转换为数字类型失败,返回 NaN,NaN 不与任何值相等,包括 NaN 自身                  
    var x = undefined, y = null;console.log(strictEqual(x,y)); console.log(abstractEqual(x,y)) false,true var x = undefined, y = null;console.log(x===y); console.log(x == y)

    false,true

    === 时, null != undefined

    == 时,规定了 null 与 undefined 的相等

    var x = true, y = 2;console.log(strictEqual(x,y)); console.log(abstractEqual(x,y)) false,false var x = true, y = 2;console.log(x === y); console.log(x == y)

     false,false

    true 转换为数字 1    

    var x = false, y = 0;console.log(strictEqual(x,y)); console.log(abstractEqual(x,y)) false,true var x = false, y = 0;console.log(x === y); console.log(x == y)

    false,true  

     false 转换为数字 0

    var x = {name:'test',valueOf:function(){return 1;}},y = 1; console.log(strictEqual(x,y));console.log(abstractEqual(x,y)); false,true var x = {name:'test',valueOf:function(){return 1;}},y = 1; console.log(x === y);console.log(x == y);

    false,true

     x.valueOf()  返回数字 1,与 y 相等

  • 相关阅读:
    Maven插件之portable-config-maven-plugin(不同环境打包)
    redis
    MySQL之group_concat 配合substring_index查询
    Jmeter执行测试计划同时监听服务器性能PerfMon Metrics Collector
    【转】证书和编码
    [转]SSL/TLS协议运行机制的概述
    OC—MVC框架图解
    安卓intent
    day8---多线程socket 编程,tcp粘包处理
    day7---socket
  • 原文地址:https://www.cnblogs.com/xinghuayang/p/JS_Equal_VS_IdentityEqual.html
Copyright © 2020-2023  润新知