Loose equality (==) and strict equality (===) are both used to determine whether two values are equal, but they have very different conditions. == allows casting in equality comparisons, while === does not. == and === both detect the type of the operand. The difference is that they are handled differently depending on the operand type.

1. Performance

  • Incorrect explanation: “== checks if values are equal, === checks if values and types are equal.” In this interpretation, === seems to do more than == because it also checks the type of the value.

  • What it says: “== allows implicit casts in equality comparisons, whereas === does not.” In this interpretation, == is a bit more work, because if the values are of different types, casts are also required.

  • One might think that == is slower than ===, but in fact, while casting does take a little longer, it is only a microsecond (millionth of a millionth) difference.

  • If the two values being compared are of the same type, == and === use the same algorithm, so there is no difference between them other than a slight difference in the JS engine implementation.

  • If the two values are of different types, we need to consider whether casting is necessary. If so, use ==, if not, use ===, regardless of performance.

2. Implicit cast in ==

2.1. General situation

2.1.1. The two values are of the same type
  • Basic types: Compare their values to see if they are equal, but note the following:

    • NaN ! = NaN
    • + 0 = = 0
  • Reference type: If two objects point to the same value, they are considered equal. No casting occurs.

    • In fact, == and === work the same way when comparing two objects.
2.1.2. Strings and Numbers
  • ES5 specification 11.9.3.4-5 Definitions:
If Type(x) is a number and Type(y) is a string, the result x==ToNumber(y) is returned. If Type(x) is a string and Type(y) is a number, ToNumber(x)==y is returned.Copy the code
  • Such as:

    (42 == '42') → (42 == 42) → true

2.1.3. Other types and Boolean types
  • ES5 specification 11.9.3.6-7 defines:
1. If Type(x) is Boolean, ToNumber(x) == y. 2. If Type(y) is a Boolean, return x == ToNumber(y).Copy the code
  • ToNumber’s results:

    • Number(true) = 1
    • Number(false) = 0
  • Take a chestnut

    • Case 1:
    var x = true;
    var y = The '42';
    // (x == y) → (1 == '42') → (1 == 42) → false
    x == y; // false
    Copy the code
    • Example 2:
    var x = The '42';
    var y = false;
    // (x == y) → ('42' == 0) → (42 == 0) → false
    x == y; // false
    Copy the code

    From the above two examples, we can see that the string ’42’ is neither true nor false, and the value is neither true nor false. Okay? Opponents! ’42’ is a true value, but no Boolean comparison occurs in the comparison ’42’ == true. Here true is converted to 1 and ’42’ is converted to 42. There is no ToBoolean involved, So whether ’42’ is true has nothing to do with == itself!

    Therefore, it is recommended that the use of == true and == false (Boolean loose equality) should be avoided in all cases.

    Note: Since === true and === false do not allow casts, ToNumber is not involved.

    • 🌰 3:
    1= =true;	  // true
    0= =false;   // true
    Copy the code
  • usage

    • Not recommended usage:
    if(a == true){ ... }  // Do not use this, the conditional judgment is not valid
    if(a === true){ ... } // Do not use this, the conditional judgment is not valid
    Copy the code
    • Suggested usage:
    if(a){ ... } 				  	// This display is fine
    if(!!!!! a){ ... }// This is a better display
    if(Boolean(a)){ ... } 	// This kind of display usage is also good
    Copy the code
2.1.4. Null and undefined
  • ES5 specification 11.9.3.2-3 defines:
If x is null and y is undefined, the result is true. If x is undefined and y is null, the result is true.Copy the code
  • Null and undefined are equal in == (they are equal to themselves), but not otherwise. That is, null and undefined are the same thing in == and can be implicitly cast to each other.
2.1.5. Objects and non-objects
  • ES5 specification 11.9.3.8-9 Defines:
If Type(x) is a string or number and Type(y) is an object, the result of x == ToPrimitive(y) is returned. If Type(x) is an object and Type(y) is a string or number, ToPrimitive(x) == y is returned.Copy the code
  • Only strings and numbers are mentioned here, not booleans, because, as explained earlier, booleans are cast to numbers first.

  • Here are some chestnuts:

    • Case 1:
    var a = 42;
    var b = [The '42'];
    
    a == b; // true
    Copy the code
    • Case 2
    0= = [];// true
    0= = [0]; // true
    0= = [' ']; // true
    0= = [null]; // true
    0= = [undefined]; // true
    0= = [false]; // false
    Copy the code
    • Example 3
    1= = [1]; // true
    1= = [true]; // false
    1= =function(){return 1; };// false
    1= =function(){return 1; } ();// true
    Copy the code
    • Example 4
    var a = 'abc';
    var b = Object('a'); // Same as new String(a)
    
    a === b; // false
    a == b;  // true, because B casts via ToPromitive (also called "unwrapping") and returns the scalar primitive value "ABC", which is equal to A.
    
    // But in some cases this is not the case because of other higher-priority rules in the == algorithm.
    Copy the code
    • Case 5
    var a = null;
    var b = Object(a); // Same as Object()
    a == b; // false
    
    var c = undefined;
    var d = Object(c); // Same as Object()
    c == d; // false
    
    // Null and undefined cannot boxed because there is no corresponding enclosing Object. Object(null) and Object() both return a regular Object.
    
    var e = NaN;
    var f = Object(e); // Same as new Number(e)
    e == f; // false
    
    // NaN can be wrapped as a digitally wrapped object, but NaN == NaN returns false after unwrapping, so false is returned.
    Copy the code

2.2. Relatively rare cases

2.2.1 Return other numbers
Case 1:
Number.prototype.valueOf = function(){
    return 3;
}
new Number(2) = =3; // true
Copy the code
  • 2 == 3 doesn’t have this problem because 2 and 3 are numeric primitives and the number.prototype.valueof () method is not called.

  • Number(2) involves a ToPrimitive cast, so valueOf() is called.

  • This is due to human causes.

Example 2:
var i = 2;
Number.prototype.valueOf = function() {
    return i++;
};
var a = new Number( 42 );
if (a == 2 && a == 3) {
    console.log( "Yep, this happened." );
}
Copy the code
  • We should use casts properly to avoid these extreme situations.
2.2.2. False value equality comparison
  • As shown (green for true, orange for false) :

  • Several of the more error-prone false values are compared equally

    '0'= =false; // true,'0'先强制类型转换为了0 → 0 == false → true
    false= =0; // true
    false= =' '; // true
    false= = [];// true
    ' '= =0; // true
    ' '= = []// true
    0= = [];// true
    Copy the code
2.2.3. Extreme cases
Case 1
[] = =! []// true
Copy the code
  • According to the ToBoolean rule, it performs an explicit cast of booleans (and reverses the parity bits).

  • So [] ==! [] becomes [] == false.

  • If false == [] = false = []

Case 2
2= = [2]; // true
Copy the code
  • [2] is converted to “2” by line ToPrimitive and then to 2 by ToNumber
Example 3
' '= = [null]; // true
Copy the code
  • [null] converts directly to “”.
Example 4
0= ='\n'; // true
Copy the code

3. Reference materials

  • Chapter 4 in JavaScript you Didn’t know (Middle volume)