JavaScript equality transitivity is weird

后端 未结 3 696
长情又很酷
长情又很酷 2020-12-01 04:08

I\'ve been reading Douglas Crockford\'s JavaScript: The Good Parts, and I came across this weird example that doesn\'t make sense to me:

\'\' == \'0\'                


        
相关标签:
3条回答
  • 2020-12-01 04:48
    '' == '0' // false
    

    The left hand side is an empty string, and the right hand side is a string with one character. They are false because it is making a comparison between two un identical strings (thanks Niall).

    0 == '' // true
    

    Hence, why this one is true, because 0 is falsy and the empty string is falsy.

    0 == '0' // true
    

    This one is a bit trickier. The spec states that if the operands are a string and a number, then coerce the string to number. '0' becomes 0. Thanks smfoote.

    false == undefined // false
    

    The value undefined is special in JavaScript and is not equal to anything else except null. However, it is falsy.

    false == null // false
    

    Again, null is special. It is only equal to undefined. It is also falsy.

    null == undefined // true
    

    null and undefined are similar, but not the same. null means nothing, whilst undefined is the value for a variable not set or not existing. It would kind of make sense that their values would be considered equal.

    If you want to be really confused, check this...

    '\n\r\t' == 0
    

    A string consisting only of whitespace is considered equal to 0.

    Douglas Crockford makes a lot of recommendations, but you don't have to take them as gospel. :)

    T.J. Crowder makes an excellent suggestion of studying the ECMAScript Language Specification to know the whole story behind these equality tests.

    Further Reading?

    The spec.

    yolpo (on falsy values)

    0 讨论(0)
  • 2020-12-01 04:59

    You can actually write a JavaScript function that behaves exactly like == that should give you some insight into how it behaves.

    To show you what I mean here is that function:

    // loseEqual() behaves just like `==`
    function loseEqual(x, y) {
        // notice the function only uses "strict" operators 
        // like `===` and `!==` to do comparisons
    
        if(typeof y === typeof x) return y === x;
    
        if(typeof y === "function" || typeof x === "function") return false;
    
        // treat null and undefined the same
        var xIsNothing = (y === undefined) || (y === null);
        var yIsNothing = (x === undefined) || (x === null);
    
        if(xIsNothing || yIsNothing) return (xIsNothing && yIsNothing);
    
        if(typeof x === "object") x = toPrimitive(x);
        if(typeof y === "object") y = toPrimitive(y);
    
        if(typeof y === typeof x) return y === x;
    
        // convert x and y into numbers if they are not already use the "+" trick
        if(typeof x !== "number") x = +x;
        if(typeof y !== "number") y = +y;
    
        return x === y;
    }
    
    function toPrimitive(obj) {
        var value = obj.valueOf();
        if(obj !== value) return value;
        return obj.toString();
    }
    

    As you can see == has a lot of complicated logic for type conversion. Because of that it's hard to predict what result you are going to get.

    Here are some examples of some results you wouldn't expect:

    Unexpected Truths

    [1] == true // returns true
    '0' == false // returns true
    [] == false // returns true
    [[]] == false // returns true
    [0] == false // returns true
    
    '\r\n\t' == 0 // returns true
    

    Unexpected Conclusions

    // IF an empty string '' is equal to the number zero (0)
    '' == 0 // return true
    
    // AND the string zero '0' is equal to the number zero (0)
    '0' == 0 // return true
    
    // THEN an empty string must be equal to the string zero '0'
    '' == '0' // returns **FALSE**
    

    Objects with Special Functions

    // Below are examples of objects that
    // implement `valueOf()` and `toString()`
    
    var objTest = {
        toString: function() {
            return "test";
        }
    };
    
    var obj100 = {
        valueOf: function() {
            return 100;
        }
    };
    
    var objTest100 = {
        toString: function() {
            return "test";
        },
        valueOf: function() {
            return 100;
        }
    };
    
    objTest == "test" // returns true
    obj100 == 100 // returns true
    objTest100 == 100 // returns true
    
    objTest100 == "test" // returns **FALSE**
    
    0 讨论(0)
  • 2020-12-01 05:01

    The answer to this question has to do with how JavaScript handles coercion. In the case of ==, strings are coerced to be numbers. Therefore:

    '' == '0' is equivalent to '' === '0' (both are strings, so no coercion is necessary).

    0 == '' is equivalent to 0 === 0 because the string '' becomes the number 0 (math.abs('') === 0).

    0 == '0' is equivalent to 0 === 0 for the same reason.

    false == undefined is equivalent to 0 === undefined because JavaScript coerces booleans to be numbers when types don't match

    false == null is equivalent to 0 === null for the same reason.

    null == undefined is true because the spec says so.

    Thanks for asking this question. My understanding of == is much better for having researched it.

    0 讨论(0)
提交回复
热议问题