zoukankan      html  css  js  c++  java
  • 你不知道的 JavaScript 系列中( 29 ) - == 和 ===

    说到 == 和 === 的区别,常见的误区是“== 检查值是否相等,=== 检查值和类型是否相等”。听起来蛮有道理,然而还不够准确。很多 JavaScript 的书籍和博客也是这样来解释的,但是很遗憾他们都错了。 正确的解释是:“== 允许在相等比较中进行强制类型转换,而 === 不允许。
     
    根据第一种解释(不准确的版本),=== 似乎比 == 做的事情更多,因为它还要检查值的类型。第二种解释中 == 的工作量更大一些,因为如果值的类型不同还需要进行强制类型转换。== 和 === 都会检查操作数的类型。区别在于操作数类型不同时它们的处理方式不同
    有人觉得 == 会比 === 慢,实际上虽然强制类型转换确实要多花点时间,但仅仅是微秒级 (百万分之一秒)的差别而已。如果进行比较的两个值类型相同,则 == 和 === 使用相同的算法,所以除JavaScript 引擎实现上的细微差别之外,它们之间并没有什么不同。如果两个值的类型不同,我们就需要考虑有没有强制类型转换的必要,有就用 ==,没有就用 ===,不用在乎性能。



    如果两个值的类型相同,就仅比较它们是否相等。例如,42 等于 42,"abc" 等于 "abc"。有几个非常规的情况需要注意:
    • NaN不等于NaN
    (12+'a' 得到 NaN,Number('123abc') 得到 NaN,NaN是一种异常的结果,也就是“not a number”,虽然它也是一个变量,但它是描述性变量,'a'不是一个数字(not a number),'b'也不是一个数字(not a number),但是'a'和'b'并不相等,所以NaN != NaN也就成立了)
    • +0等于-0
    (保留 0 值的符号位防止方向信息丢失, 数学角度讲 0 的相反数是它本身)



    字符串和数字之间的比较
    var a = 42;
    var b = "42";
    a === b; // false
    a == b; // true

    因为没有强制类型转换,所以 a === b 为 false,42 和 "42" 不相等。而a == b是宽松相等,即如果两个值的类型不同,则对其中之一或两者都进行强制类型转换。"42"被强制类型转换为数字以便进行相等比较



    其他类型和布尔类型之间的相等比较
    var a = "42";
    var b = true;
    a == b; // false
    我们都知道 "42" 是一个真值,为什么 == 的结果不是 true 呢? 遇到布尔值,布尔值先转Number类型。将 true 强制类型转换为 1,变成 1 == "42", 二者的类型仍然不同,"42" 根据规则被强制类型转换为 42,最后变成 1 == 42,结果为 false。
    var x = "42";
    var y = false;
    x == y; // false
    将 false 强制类型转换为 0,然后 "42" == 0, 再变成,42 == 0,结果为 false。也就是说,字符串 "42" 既不等于 true,也不等于 false。
    无论什么情况下都不要使用 == true 和 == false。请注意,这里说的只是 ==, === true 和 === false不允许强制类型转换,所以并不涉及 ToNumber。
    例如:
    var a = "42";
    // 不要这样用,条件判断不成立:
    if (a == true) {
        // .. 
    }
    
    // 也不要这样用,条件判断不成立:
    if (a === true) {
        // .. 
    }
    
    // 这样的显式用法没问题:
    if (a) {
        // .. 
    }
    
    // 这样的显式用法更好:
    if (!!a) {
        // .. 
    }
    
    // 这样的显式用法也很好:
    if (Boolean( a )) {
        // .. 
    }

    避免了 == true 和 == false(也叫作布尔值的宽松相等)之后我们就不用担心这些坑了。



    null 和 undefined 之间的相等比较
    在 == 中 null 和 undefined 相等(它们也与其自身相等),除此之外其他值都不存在这种情况。
    这也就是说在 == 中 null 和 undefined 是一回事,可以相互进行隐式强制类型转换:
    var a = null;
    var b;
    a == b; // true
    a == null; // true
    b == null; // true
    a == false; // false
    b == false; // false
    a == ""; // false
    b == ""; // false
    a == 0; // false
    b == 0; // false
    
    var a = doSomething();
    if (a == null) {
      // ..
    }

    条件判断 a == null 仅在doSomething()返回非 null 和 undefined 时才成立,除此之外其他值都不成立,包括 0、false 和 "" 这样的假值。 下面是显式的做法,其中不涉及强制类型转换,个人感觉更繁琐一些(大概执行效率也会更低):

    var a = doSomething();
    if (a === undefined || a === null) {
      // ..
    }
    我认为 a == null 这样的隐式强制类型转换在保证安全性的同时还能提高代码可读性。



    对象和非对象之间的相等比较
    var a = 42;
    var b = [ 42 ];
    a == b; // true
    [ 42 ] 首先调用 ToPromitive 抽象操作(参见 4.2 节),返回 "42",变成 "42" == 42,然后 又变成 42 == 42,最后二者相等。
    var a = "abc";
    var b = Object( a );
    a == b; // true
    结果为true,因为 b 通过 ToPromitive 进行强制类型转换,并返回标量基本类型值 "abc",与 a 相等。
    假值的相等比较
    "0" == null; // false
    "0" == undefined; // false
    "0" == false; // true
    "0" == NaN; // false
    "0" == 0; // true
    "0" == ""; // false
    
    
    false == null; // false
    false == undefined; // false
    false == NaN; // false
    false == 0; // true
    false == ""; // true
    false == []; // true
    
    
    false == {}; // false
    "" == null; // false
    "" == undefined; // false
    "" == NaN; // false
    "" == 0; // true
    "" == []; // true
    
    
    "" == {}; // false
    0 == null; // false
    0 == undefined; // false
    0 == NaN; // false
    0 == []; //true
    0 == {}; // false
    如果不小心碰到 doSomething(0) 和 doSomething([]) 这样的情况,结果会让你大吃一惊。 又如:
    function doSomething(a,b) {
      if (a == b) {
        // ..
      }
    }

    doSomething("",0) 和 doSomething([],"") 也会如此。

    这些特殊情况会导致各种问题,我们要多加小心,好在它们并不十分常见。
    有一种情况下强制类型转换是绝对安全的,那就是 typeof 操作。typeof 总是 返回七个字符串之一(参见第 1 章),其中没有空字符串。所以在类型检查过程中不会发生隐式强制类型转换。typeof x == "function"是100%安全 的,和typeof x === "function"一样。事实上两者在规范中是一回事。所 以既不要盲目听命于代码工具每一处都用 ===,更不要对这个问题置若罔闻。 我们要对自己的代码负责。
    我们要对 == 两边的值认真推敲,以下两个原则可以让我们有效地避免出错。
    • 如果两边的值中有 true 或者 false ,千万不要使用==。
    • 如果两边的值中有[]、"" 或者 0,尽量不要使用 ==。这时最好用 === 来避免不经意的强制类型转换。这两个原则可以让我们避开几乎所有强制 类型转换的坑



    总结:
    1、• NaN不等于NaN ,• +0等于-0
    2、字符串和数字 == 比较,字符串被强制类型转换为数字再进行比较
    3、== 中遇到布尔值,布尔值先转 Number 类型
    4、== 中 null 和 undefined 是一回事,可以相互进行隐式强制类型转换,除此之外其他值都不存在这种情况
    5、== 中,遇到对象,对象先转字符串,再转数字类型 []=>Number[]=>0,[42]=>Number([42])=>42
  • 相关阅读:
    概率算法_二项分布和泊松分布
    数据库_存储过程简介(oracle版)
    机器学习算法_knn(福利)
    统计算法_概率基础
    统计算法_数值/线性关系度量
    Python总结
    Python 冒泡排序法分析
    Oracle练习详解
    LINUX基础了解
    LINUX下OA搭建
  • 原文地址:https://www.cnblogs.com/wzndkj/p/14048452.html
Copyright © 2011-2022 走看看