Equality judgment in JavaScript

Equality judgment in JavaScript

There are four equality algorithms in ES2015:

  • Abstract (non strict) equality comparison (= =)
  • Strict equality comparison (= = =): for array prototype. indexOf, Array.prototype.lastIndexOf, and {case matching
  • Same value zero: used for% TypedArray% and% ArrayBuffer constructors, as well as Map and Set operations, and will be used for string in ES2016/ES7 prototype. includes
  • Same value: for all other places

JavaScript provides three different value comparison operations:

  • Strict equality comparison (also known as "strict equality", "identity", "triple equals") uses === ,
  • Abstract equality comparison ("loose equality", "double equals"), using ==
  • And Object.is (ECMAScript 2015/ ES6 new features)

The choice of which operation to use depends on what kind of comparison you need.

In short, when comparing two things, the double equal sign performs type conversion; The equal sign will make the same comparison without type conversion (if the types are different, it will always return false); And object The behavior of is is is the same as that of the triple sign, but special treatment is made for NaN and - 0 and + 0, so the last two are different, and object Is (NaN, NaN) will be true. (NaN is usually compared with NaN with double or triple sign, and the result is false, because IEEE 754 says so.) Note that all these differences are related to their processing primitives; None of the primitives of the three operators will compare whether the two variables are structurally similar. For any two different non original objects, even if they have the same structure, the above three operators will calculate false.

Strict equality===

Congruent operators compare whether two values are equal, and the two compared values are not implicitly converted before comparison. If two compared values have different types, the two values are not congruent. Otherwise, if the two compared values have the same type and the same value, and neither of them is of type number, the two values are equal. Finally, if both values are of type number, both values are considered congruent when they are not NaN and the values are the same, or when the two values are + 0 and - 0 , respectively.

<span style="color:#1b1b1b"><span style="background-color:#ffffff"><span style="background-color:#f4f4f4"><code><span style="color:#005282">var</span> num <span style="color:#1b1b1b">=</span> <span style="color:#a30008">0</span><span style="color:#6d6d6d">;</span>
<span style="color:#005282">var</span> obj <span style="color:#1b1b1b">=</span> <span style="color:#005282">new</span> <span style="color:#db000e">String</span><span style="color:#6d6d6d">(</span><span style="color:#005a38">"0"</span><span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span>
<span style="color:#005282">var</span> str <span style="color:#1b1b1b">=</span> <span style="color:#005a38">"0"</span><span style="color:#6d6d6d">;</span>
<span style="color:#005282">var</span> b <span style="color:#1b1b1b">=</span> <span style="color:#a30008">false</span><span style="color:#6d6d6d">;</span>

console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>num <span style="color:#1b1b1b">===</span> num<span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// true</span>
console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>obj <span style="color:#1b1b1b">===</span> obj<span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// true</span>
console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>str <span style="color:#1b1b1b">===</span> str<span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// true</span>

console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>num <span style="color:#1b1b1b">===</span> obj<span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// false</span>
console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>num <span style="color:#1b1b1b">===</span> str<span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// false</span>
console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>obj <span style="color:#1b1b1b">===</span> str<span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// false</span>
console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span><span style="color:#005282">null</span> <span style="color:#1b1b1b">===</span> <span style="color:#005282">undefined</span><span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// false</span>
console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>obj <span style="color:#1b1b1b">===</span> <span style="color:#005282">null</span><span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// false</span>
console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>obj <span style="color:#1b1b1b">===</span> <span style="color:#005282">undefined</span><span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// false</span>
</code></span></span></span>
Copy to Clipboard

Using congruent operators in everyday life is almost always the right choice. For values other than numeric values, the congruence operator uses explicit semantics for comparison: a value is congruent only with itself. For numeric values, the congruent operator uses slightly modified semantics to deal with two special cases: the first case is that the floating-point number 0 is not positive or negative. Distinguishing between + 0 and - 0 is necessary to solve some specific mathematical problems, but in most cases we don't care. The congruent operator considers these two values congruent. The second case is that floating-point numbers contain NaN values, which are used to represent the solutions of some undefined mathematical problems, such as positive infinity plus negative infinity. The congruent operator considers NaN to be congruent with any other value, including itself. (the only case where equation (x! = = x) holds is that the value of X is NaN)

Non strict equality==

The equality operator compares whether two values are equal and converts the two compared values to the same type before comparison. After conversion (one or both sides of the equation may be converted), the final comparison method is the same as that of the congruent operator = =. The equality operator satisfies the commutative law.

The comparison of different types of values by the equality operator is shown in the following figure:

Compared value B
UndefinedNullNumberStringBooleanObject
Compared value AUndefinedtruetruefalsefalsefalseIsFalsy(B)
NulltruetruefalsefalsefalseIsFalsy(B)
NumberfalsefalseA === BA === ToNumber(B)A=== ToNumber(B)A== ToPrimitive(B)
StringfalsefalseToNumber(A) === BA === BToNumber(A) === ToNumber(B)ToPrimitive(B) == A
BooleanfalsefalseToNumber(A) === BToNumber(A) === ToNumber(B)A === BToNumber(A) == ToPrimitive(B)
ObjectfalsefalseToPrimitive(A) == BToPrimitive(A) == BToPrimitive(A) == ToNumber(B)

A === B

In the above table, ToNumber(A) attempts to convert parameter A to A number before comparison, which has the same effect as + A (monocular operator +). ToPrimitive(A) converts parameter A to A Primitive value by trying to call A's A.toString() and A.valueOf() methods.

Generally speaking, according to ECMAScript specification, all objects are not equal to "undefined" and "null". However, most browsers allow A very narrow class of objects (that is, the , document.all , object in all pages) to act as an example of , undefined , in some cases. The equality operator is in this context. Therefore, the value of isfalse (A) method is , true if and only if , A , emulates , undefined. In all other cases, an object will not be equal to 'undefined' or 'null'.

<span style="color:#1b1b1b"><span style="background-color:#ffffff"><span style="background-color:#f4f4f4"><code><span style="color:#005282">var</span> num <span style="color:#1b1b1b">=</span> <span style="color:#a30008">0</span><span style="color:#6d6d6d">;</span>
<span style="color:#005282">var</span> obj <span style="color:#1b1b1b">=</span> <span style="color:#005282">new</span> <span style="color:#db000e">String</span><span style="color:#6d6d6d">(</span><span style="color:#005a38">"0"</span><span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span>
<span style="color:#005282">var</span> str <span style="color:#1b1b1b">=</span> <span style="color:#005a38">"0"</span><span style="color:#6d6d6d">;</span>
<span style="color:#005282">var</span> b <span style="color:#1b1b1b">=</span> <span style="color:#a30008">false</span><span style="color:#6d6d6d">;</span>

console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>num <span style="color:#1b1b1b">==</span> num<span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// true</span>
console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>obj <span style="color:#1b1b1b">==</span> obj<span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// true</span>
console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>str <span style="color:#1b1b1b">==</span> str<span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// true</span>

console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>num <span style="color:#1b1b1b">==</span> obj<span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// true</span>
console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>num <span style="color:#1b1b1b">==</span> str<span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// true</span>
console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>obj <span style="color:#1b1b1b">==</span> str<span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// true</span>
console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span><span style="color:#005282">null</span> <span style="color:#1b1b1b">==</span> <span style="color:#005282">undefined</span><span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span> <span style="color:#6d6d6d">// true</span>

<span style="color:#6d6d6d">// both false, except in rare cases</span>
console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>obj <span style="color:#1b1b1b">==</span> <span style="color:#005282">null</span><span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span>
console<span style="color:#6d6d6d">.</span><span style="color:#db000e">log</span><span style="color:#6d6d6d">(</span>obj <span style="color:#1b1b1b">==</span> <span style="color:#005282">undefined</span><span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span>
</code></span></span></span>
Copy to Clipboard

Some developers believe that it is best never to use the equality operator. The results of congruent operators are easier to predict, and congruent comparison is faster because there is no implicit conversion.

Equal value

Equality of values solves the last use case: determining whether two values are functionally identical in any case. (this use case demonstrates Richter substitution principle Examples of.) What happens when you try to modify an immutable attribute:

<span style="color:#1b1b1b"><span style="background-color:#ffffff"><span style="background-color:#f4f4f4"><code><span style="color:#6d6d6d6d "> / / add an immutable attribute new_zero to the Nmuber constructor</span>
Object<span style="color:#6d6d6d">.</span><span style="color:#db000e">defineProperty</span><span style="color:#6d6d6d">(</span>Number<span style="color:#6d6d6d">,</span> <span style="color:#005a38">"NEGATIVE_ZERO"</span><span style="color:#6d6d6d">,</span>
                      <span style="color:#6d6d6d">{</span> value<span style="color:#1b1b1b">:</span> <span style="color:#1b1b1b">-</span><span style="color:#a30008">0</span><span style="color:#6d6d6d">,</span> writable<span style="color:#1b1b1b">:</span> <span style="color:#a30008">false</span><span style="color:#6d6d6d">,</span> configurable<span style="color:#1b1b1b">:</span> <span style="color:#a30008">false</span><span style="color:#6d6d6d">,</span> enumerable<span style="color:#1b1b1b">:</span> <span style="color:#a30008">false</span> <span style="color:#6d6d6d">}</span><span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span>

<span style="color:#005282">function</span> <span style="color:#db000e">attemptMutation</span><span style="color:#6d6d6d">(</span>v<span style="color:#6d6d6d">)</span>
<span style="color:#6d6d6d">{</span>
  Object<span style="color:#6d6d6d">.</span><span style="color:#db000e">defineProperty</span><span style="color:#6d6d6d">(</span>Number<span style="color:#6d6d6d">,</span> <span style="color:#005a38">"NEGATIVE_ZERO"</span><span style="color:#6d6d6d">,</span> <span style="color:#6d6d6d">{</span> value<span style="color:#1b1b1b">:</span> v <span style="color:#6d6d6d">}</span><span style="color:#6d6d6d">)</span><span style="color:#6d6d6d">;</span>
<span style="color:#6d6d6d">}</span>
</code></span></span></span>
Copy to Clipboard

Object.defineProperty: when trying to modify an immutable property, if the property is indeed modified, an exception will be thrown. Otherwise, nothing will happen. For example, if v is - 0, nothing changes, so no exceptions are thrown. However, if v is + 0, an exception is thrown. The immutable attribute and the newly set value are compared using the same value equality.

The same value is equal by Object.is Methods are provided.

Zero values are equal

It is similar to the same value, but + 0 and - 0 will be considered equal.

Equality, strict equality and equality of equal value in specifications

In ES5 == Equal in Section 11.9.3, The Abstract Equality Algorithm; === Equal in 11.9.6, The Strict Equality Algorithm . (please refer to these two links. They are very concise and easy to understand. Tip: please read the strict equality algorithm first.) ES5 also provides the same value equality Section 9.12, The SameValue Algorithm , used inside the JS engine. Except for the difference in processing numbers between 11.9.6.4 and 9.12.4, it is basically the same as the strict equality algorithm. ES6 simply passes Object.is This algorithm is exposed.

We can see that when using double or third class, in addition to the type check in 11.9.6.1, the strict equality algorithm is a subset of the equality algorithm, because 11.9.6.2 – 7 corresponds to 11.9.3.1 a–f.

Understand the model of equality comparison

Before ES2015, you might say that double and third are "extended" relationships. For example, some people will say that double class is an extended version of third class, because it handles what third class does and makes type conversion. For example, 6 = = "6". On the contrary, others may say that third class is a double class extension, because it also requires the same type of two parameters, so more restrictions are added. How you understand it depends on how you look at it.

However, this method of comparison can't make the ES2015} Object.is Arrange into it. Because Object.is It is not more relaxed than double class, nor more strict than third class. Of course, it is not among them. As can be seen from the table below, this is due to Object.is Handle NaN Different. Note that if the object If is (Nan, Nan) is calculated as false, we can say that it is more strict than third class because it can distinguish between - 0 and + 0. But yes NaN The treatment shows that this is wrong.   Object.is It should be considered to have its special purpose, and it should not be said that it is equal to others, more relaxed or strict.

Judgment, etc
xy=====Object.is
undefinedundefinedtruetruetrue
nullnulltruetruetrue
truetruetruetruetrue
falsefalsetruetruetrue
"foo""foo"truetruetrue
00truetruetrue
+0-0truetruefalse
0falsetruefalsefalse
""falsetruefalsefalse
""0truefalsefalse
"0"0truefalsefalse
"17"17truefalsefalse
[1,2]"1,2"truefalsefalse
new String("foo")"foo"truefalsefalse
nullundefinedtruefalsefalse
nullfalsefalsefalsefalse
undefinedfalsefalsefalsefalse
{ foo: "bar" }{ foo: "bar" }falsefalsefalse
new String("foo")new String("foo")falsefalsefalse
0nullfalsefalsefalse
0NaNfalsefalsefalse
"foo"NaNfalsefalsefalse
NaNNaNfalsefalsetrue

When to useObject.is Or third class

In general, in addition to treatment NaN In a way, Object.is The only interesting thing is the special way it treats 0 when you need some metaprogramming scheme, especially about the attribute descriptor, that is, your work needs to be mirrored Object.defineProperty Some features of. If you don't need these for your job, you should avoid them Object.is , use === Instead. Even if you need to compare two NaN Make the result true. Generally speaking, it is written and used NaN Special case function for checking (using the old version of ECMAScript) isNaN method )It's better than coming up with some calculations Object.is It is easier to compare zeros that do not affect different symbols.

Here is an incomplete list of built-in methods and operators that treat - 0 and + 0 differently:

-(unitary negative)

Obviously, a unary negative operation on 0 yields - 0. However, the abstraction of expressions may lead to - 0 continuous propagation without your awareness. For example, when considering the following example:

<span style="color:#1b1b1b"><span style="background-color:#ffffff"><span style="background-color:#f4f4f4"><code><span style="color:#005282">let</span> stoppingForce <span style="color:#1b1b1b">=</span> obj<span style="color:#6d6d6d">.</span>mass <span style="color:#1b1b1b">*</span> <span style="color:#1b1b1b">-</span>obj<span style="color:#6d6d6d">.</span>velocity</code></span></span></span>
Copy to Clipboard

If obj Velocity is 0 (or the calculation result is 0). A - 0 is generated at the top and assigned as the value of stoppingForce

Math.atan2

Math.ceil

Math.pow

Math.round

Even if there is no - 0 in the passed in parameter, the return value of these methods may be - 0. For example, when using Math.pow Calculate- Infinity The power of any negative odd exponent of will get - 0. Please refer to the respective documentation of these methods for details.

Math.floor

Math.max

Math.min

Math.sin

Math.sqrt

Math.tan

These methods may also return - 0 when there is - 0 in the passed in parameter. For example, math Min (- 0, + 0) yields - 0. Please refer to the respective documentation of these methods for details.

~

<<

>>

ToInt32 algorithm is used inside these operators. Because the internal 32-bit integer type has only one 0 (no sign difference), the symbol of - 0 will not be retained after the reverse operation. For example, object Is (~ ~ (- 0), - 0) and object Is (- 0 < < 2 > > 2, - 0) will get false

Dependent on without considering the sign of 0 Object.is It's dangerous. Of course, if the original intention is to distinguish between - 0 and + 0, Object.is Able to complete the work as expected.

Keywords: Javascript

Added by bradley252 on Mon, 03 Jan 2022 23:24:30 +0200