• JavaScript == 和 ===


    JavaScript == 和 ===

     

    == 操作符(Equality,相等操作符)

    相等操作符会做类型转换。

    我们先来看看什么是类型转换(type coercion)

    当操作符两边的操作数是不同类型时,其中一个操作数将转换为另一个操作数同类型的“等效”值。比如:

    12 - '3' // 9, 将 string 类型转换成 number 类型,相当于 12 - Number('3')
    12 - 'hello' // NaN, 因为 Number('hello') 为 NaN,12 - NaN 为 NaN
    '3' - 12 // -9, 同样转成 number 类型
    12 - true // 11, Number(true) 为 1
    false - 12 // -12, Number(false) 为 0
    12 + '3' // 123, 将 12 转换成 string 类型,再连接 '3'

    看上去很简单对不对?减法将非 number 类型的转换成 number 类型的,加法将 number 类型转换成 string 类型的,真的这样吗?看下面:

    12 + true // 13,这里将布尔类型 true 转换成数值类型 1,相当于 12 + Number(true)

    从上面可以看出,“加法将 number 类型 转换成 string 类型”这个总结并不正确,事实上,类型转换并不单单看操作符,也就是并不只是看你做加法还是做减法,还要看你的类型,我们从上面的规律中做下总结:

    • number - string 将 string 转换成 number
    • string - number 将 string 转换成 number
    • number - boolean 将 boolean 转成 number
    • boolean - number 将 boolean 转成 number
    • number + string 将 number 转成 string
    • number + boolean 将 boolean 转成 number
    • ...

    有点眼花,也不是很有规律。有时候类型转换还可能会调用 toString 方法,加上操作符有很多,像 +、-、*、/、%、==、=== 等等,再加上 5 种基本数据类型 Number、String、Undefined、Null、Boolean,还有引用类型 Object,这样组合起来,类型转换的规律就很难掌握了。

    比如下面这个:

    [1] - 3 // -2, 相当于 Number([1].toString()) - 3
    [1, 2, 3] - 3 // NaN, 这里 toString 之后 会得到 '1,2,3',转成 number 就是 NaN
    [[]] - 3 // -3, [[]].toString 是 "","" 转成 number 类型是 0
    5 * '1' // 5, Number('1') 为 1
    5 * 'true' // NaN, Number('true') 为 NaN
    5 * true // 5, Number(true) 为 1

    是不是觉得规则已经比较难记忆了?

    回到我们的 == 操作符

    相等操作符在比较时,如果左右两边的类型不同,也会将左边或者右边的操作数转换成与对方同类型的等效值。比如:

    12 == "12" // true, string 类型转换成 number 类型
    1 == true // true, boolean 类型转换成 number 类型
    true == '1' // true, 两者都转换成 number 再比较? 还是 '1' 转换成 boolean 类型?
    true == '2' // false?? Boolean('2') 可是等于 true 哦,结合上面一条语句,可以得出应该是两者都转换成 number 再比较

    再来看看 == 操作符的传递性

    0 == '' // true
    0 == '0' // true
    '' == '0' // false

    可以看出,== 操作符不满足传递性

    再来看几个例子:

    false == 'false'    // false
    false == '0'        // true
    
    false == undefined  // false
    false == null       // false
    null == undefined   // true
    
    ' 	
     ' == 0     // true

    是不是觉得还能理解,但可能记不住了?所以,如果你不了解所有的规则,最好不要使用相等操作符,而是使用恒等操作符,下面这张图比较有说服力,来自 dorey.github.io,绿色表示相等操作符运算后结果为 true:
    相等操作符

    规则这么多,掌握不好容易出错。

    === 操作符(Identity,恒等操作符)

    很多人认为恒等操作符代表值相等,并且有相同的类型,但这是不对的,来看下面的例子:

    var a = [1, 2, 3],
        b = [1, 2, 3],
        c = {},
        d = {};
    console.log(a === b); // false
    console.log(c === d); // false

    可见,即使是相同的类型,而且值相等,也不一定恒等。

    恒等

    恒等操作符有三种情况:

    1. 两个操作数都是引用类型,他们都引用同一个 object,即地址相同,则恒等成立。
    2. 两个操作数都是基本数据类型 (Boolean、Number、String、Undefined、Null),如果值相同,则恒等成立。
    3. 一个操作数是引用类型,另一个是基本数据类型,恒等不成立。

    上面的例子不等是因为地址不同。我们再来看看比较特殊的 String:

    String 的基本数据类型和基本包装类型

    我们知道,基本数据类型不是引用类型,应该是没有方法的,比如 'hello world',但你确实可以用 'hello world'.split("") 分割字符串,这是因为调用 split 这个方法的时候,后台就会创建一个基本包装类型的对象 (new String('hello world')),我们实质上是从这个基本包装类型里获取的方法,这样的基本包装类型还有 Boolean 和 Number。

    要明确,'hello world' 只是一个基本数据类型,不管它是拼接而成还是直接以字面量的形式形成,比如:

    var a = 'hello' + ' world',
        b = 'hello world';
    console.log(a === b); // true

    因为 a、b都是基本数据类型,所以直接比较值,是相等的,那么恒等成立。

    但如果是这样:

    var a = 'hello world',
        b = new String('hello world');
    console.log(a === b); // false, 因为 a 是基本数据类型,b 是引用类型,恒等不成立。

    来看一下恒等操作符的比较情况:
    恒等操作符

    所以 Douglas Crockford 建议我们永远不使用 == 操作符,而是使用 === 操作符

    另外,在引用类型的比较上 == 和 === 的表现还是一致的,因为不论是否有类型转换,值都是地址,即比较的都是地址,地址相同则相同,如有不对,还望指出:

    var a = [1, 2, 3],
        b = [1, 2, 3],
        c = {},
        d = {},
        e = a;
    console.log(a === b); // false
    console.log(c === d); // false
    console.log(a == b); // false
    console.log(c == d); // false
    console.log(a == e); // true
    console.log(a === e); // true
    console.log([0] == (new String("0"))); // false
    console.log([0] === (new String("0"))); // false

    参考
    Which equals operator (== vs ===) should be used in JavaScript comparisons?
    JavaScript-Equality-Table
    《JavaScript 高级程序设计》

    智辉 所有文章遵循“创作共用版权协议”(知识共享许可协议),要求 署名-非商业使用-禁止演绎 (by-nc-nd)。在满足创作共用版权协议的基础上可以转载,但请以超链接形式注明出处并保留此段声明。

     

  • 相关阅读:
    brew一直卡在Updating Homebrew的解决办法
    ELK5.6.4+Redis+Filebeat+Nginx(CentOS7.4)
    CentOS7.3 ffmpeg安装
    nginx Dockerfile
    pip安装第三方包超时
    logrotate nginx日志切割
    Ansible部署zabbix-agent
    Zabbix主动模式和被动模式
    Zabbix添加监控主机
    Zabbix3.2安装
  • 原文地址:https://www.cnblogs.com/libin-1/p/6001619.html
Copyright © 2020-2023  润新知