The secret you don’t know in JavaScript loose equality (==)

Preface

In daily JavaScript development, we often use relaxed equality (==) and strict equality (===) to determine whether two values ​​are "equal", but there is a very important difference between them, especially in determining conditions on.

So what is the difference between them? I think many people will blurt out: == compares the value to be equal, === will judge whether the value and the type are equal. It sounds reasonable, but it's still not accurate enough.

The correct explanation is: == allows forced type conversion in the judgment of equality, and === does not allow.

But do you understand that == is the specific rule for forced type conversion in the judgment? In the ES5 specification, the "abstract equality comparison algorithm" is mentioned, and the behavior of the == operator is defined.

1. Comparison rules

1.1 Equality comparison between the same type

When the data types on the left and right sides of == are the same, directly compare whether the values ​​are equal. Except NaN, because NaN is the only reflexive data.

1.2 Equality comparison between string and number

Let us now give an example:

      var a = '42'
      var b = 42
      console.log(a == b) // true
      console.log(a === b) // false

Everyone knows that == will output true, and === will output false. Because == has undergone a coercive type conversion, but do you know whether a is coerced into a number, or is it coerced into a string? ?

This is defined in the ES5 specification:

  1. If type(x) is a number and type(y) is a string, the result of x==toNumber(y) is returned.
  2. If type(x) is a string and type(y) is a number, the result of toNumber(x)==y is returned.

So according to the specification, the above example should convert the value of a '42' to the number 42 for comparison.

1.3 Equality comparison between other values ​​and Boolean values

== The most error-prone thing is to compare false and true with other types of values.

E.g:

      var a = '42'
      var b = true
      console.log(a==b) // false

We all know that '42' is true, but why is it false?

This is what it says in the ES5 specification:

  1. If type(y) is a Boolean value, the result of x==toNumber(y) is returned.
  2. If type(x) is a Boolean value, the result of toNumber(x) == y is returned.

So the appeal example should convert b to the number 1, which is a relative comparison between a string and a number. According to the specification in 1.2 above, the string '42' is converted to a number 42. 42 is not equal to 1, so the result is false .

Of course, the reverse is also true:

      var a = true
      var b = '42'
      console.log(a == b) // false

Seeing this, do you have a question: Why is "42" neither equal to true nor equal to false?

"42" itself is a true value (true), but the question itself is wrong. Because when comparing here, instead of converting "42" into a Boolean value, but converting the Boolean value to the corresponding digital representation (0 or 1), the final result will be false.

1.3 Equality comparison between null and undefined

In the ES5 specification it says:

  1. If x is null and y is undefined, then x == y is true.
  2. If x is undefined and y is null, then x == y is true.
      var a = null
      var b
      console.log(a == b) // true
      console.log(a == null) // true
      console.log(b == null) // true
      console.log(a == undefined) // true
      console.log(b == undefined) // true

      console.log(a == '') // false
      console.log(b == '') // false
      console.log(b == false) // false
      console.log(b == false) // false

In other words, in ==, null and undefined are the same thing.

1.4 Equality comparison between objects and non-objects

The following provisions are made in ES5:

  1. If type(x) is a string or number, and type(y) is an object, the result of x == ToPrimitive(y) is returned 
  2. If type(x) is an object and type(y) is a string or a number, the result of ToPrimitive(x) == y is returned 

There is no mention of Boolean values ​​here, because the Boolean value is first converted to a number when it encounters a Boolean value.

      var a = '42'
      var b = [42]
      console.log(a == b) // true

Here, b first calls ToPrimitive, returns 42, and then converts '42' to the number 42, and finally 42 == 42, the result is true.

Here are a few things to pay attention to:

      var a = null
      var b = Object(a)
      console.log(a == b) // false

      var c = undefined
      var d = Object(c)
      console.log(c == d) // false

      var e = NaN
      var f = Object(e)
      console.log(e == f) // false

Because there is no corresponding encapsulated object, null and undefined cannot be encapsulated. Object(null) and Object() both return a regular object.

NaN can be encapsulated by digital objects, and NaN is reflexive data, so after splitting, return false.

Of course, there are also several special requests, such as:

      console.log(0 == '') // true
      console.log(0 == []) // true
      console.log([] == '') // true

If loose equality is used improperly, it will bring us a lot of trouble. Therefore, the use of loose equality should abide by the following two principles, which can avoid unnecessary errors for us:

  1. If the values ​​on both sides are true or false, never use ==.
  2. If the values ​​on both sides have [], "", 0, try not to use ==.

1.5 Comparison of abstract relations

The implicit coercion in abstract relationship comparison may not be noticeable, but if you want to become a good JavaScript developer, you should learn more about it.

This is defined in the ES5 specification: the abstract relationship comparison is divided into two parts, the comparison of both sides is a string and other situations.

1.5.1 Other situations

 Both parties of the comparison call ToPromitive first, if the result is a non-string, call ToNumber to force the two parties to be converted to numbers for comparison.

E.g:

      var a = [42]
      var b = ['43']
      console.log(a < b) // true

If both sides of the comparison are strings, compare them in alphabetical order

      var a = ['42']
      var b = ['043']
      console.log(a < b) // false

ToPromitive returns a string, a and b are not converted into numbers, so the string '42' and the string '043' are compared. Because the '0' is before the '4', it returns false.

So what will this example return?

      var a = { b: '42' }
      var b = { b: '043' }
      console.log(a < b) // ???

Still false, because a is [object Object] and b is also [object Object], so a <b is not true.

Pay attention here, something magical is about to happen, please see the following example:

      var a = { b: '42' }
      var b = { b: '043' }
      console.log(a < b) // false
      console.log(a > b) // false
      console.log(a == b) // false
      console.log(a <= b) // true
      console.log(a >= b) // true

Why a==b and a<b are both false, but a<=b and a>=b are true?

Because according to the ES5 specification, a<=b is processed as b<a, and then the result is reversed, because the result of b<a is false, the result is true.

Why is a == b true here? Isn't it the same as [object Object]?

Here should be judged according to the above-mentioned type equality, if the same object, it will judge whether the value pointed to by the object is equal, and no forced type conversion occurs.

At last

Now we have understood some of the "pits" in loose equality, and I believe that everyone will not enter these "pits" in future development.

Now, do you have a question: when to use "==" and when to use "==="

It is mentioned in the book "JavaScript You Don't Know (Chinese)":

  1. If you compare two values ​​of the same type, == and === will use the same algorithm, so there is no difference between them except for some subtle differences in the JavaScript engine.
  2. If comparing two values ​​with different types, we need to consider whether there is a comparison of forced type conversion, if there is a comparison, use ==, if not, use ===, do not care about performance.

 

 

 

 

 

Guess you like

Origin blog.csdn.net/qq_44313091/article/details/108197229