JavaScript developer Douglas Crockford once referred to the JavaScript ==
and !=
operators as "evil twins" that should be avoided. However, once you understand them, these operators aren't that bad and can actually be useful. This article will explore ==
and !=
, explain how they work, and help you understand them better.
Key Points
-
Understanding the basics: and
==
operators in JavaScript are not inherently evil; they perform type casts when comparing different types of values, which is both useful and tricky.!=
- Learn when to use which one: Use and
===
for direct type and value comparisons without casting, which is clearer and it is usually recommended to avoid unexpected results. Use!==
and==
when you need to cast or compare values whose types may change dynamically.!=
- Learn the cast rules: Familiar with how JavaScript casts types during and
==
comparisons, so as to predict results more accurately and avoid common pitfalls.!=
- Explore practical examples: Dig into the examples to see how and
==
run in various scenarios, such as comparing strings to numbers or objects to original values, to consolidate understanding .!=
- Don't be afraid, but be cautious: Although and
==
are not scary, they require a good understanding of JavaScript's type cast rules to be effective and safe in code Use it locally.!=
Problematic and ==
operators !=
and ===
, and !==
and ==
. Understanding why there are two sets of equality operators and in which situations to use which operator has been the source of confusion for many people. The !=
and ===
operators are not difficult to understand. When the two operand types are the same and the values are the same, !==
returns ===
and true
returns !==
. However, when the value or type is different, false
returns ===
, false
returns !==
. The true
and ==
operators behave the same when the two operand types are the same. However, when the types are different, JavaScript casts one operand !=
to another type to make the operand compatible before comparison. The results are often confusing, as follows:
"this_is_true" == false // false "this_is_true" == true // false. However, they are all calculated as
. Additional confusion occurs when you assume that the pass relationship (if a is equal to b and b is equal to c) should apply: true
"this_is_true" == false // false "this_is_true" == true // false
This example shows that ==
lacks transitiveness. If the empty string is equal to the number 0, and if the number 0 is equal to the string composed of character 0, the empty string should be equal to the string composed of 0. But that's not the case. When an incompatible type is encountered when comparing operands through ==
or !=
, JavaScript casts one type to another to make it comparable. Conversely, when using ===
and !==
, it never performs type casts (which leads to a slight improvement in performance). Due to different types, ===
always returns false
in the second example. Understanding rules that control how JavaScript casts operands to different types so that the two operand types are compatible before applying ==
and !=
can help you determine when it is better to use ==
and !=
, and Have confidence in using these operators. In the next section, we will explore the cast rules used with the ==
and !=
operators.
==
and !=
work?
and ==
work is to study the ECMAScript language specifications. This section focuses on ECMAScript 262. Section 11.9 of the specification introduces the equality operator. The !=
and ==
operators appear in the syntax production !=
and EqualityExpression
. (Unlike the first generation, the second generation avoids the EqualityExpressionNoIn
operator.) Let's check the in
generation shown below. EqualityExpression
'' == 0 // true 0 == '0' // true '' == '0' // falseAccording to this generation, the equal expression is either a relational expression, or an equal expression that is equal to a relational expression, or an equal expression that is not equal to a relational expression, etc. . (I overlooked
and ==
, which are not related to this article.) Section 11.9.1 provides the following information on how !=
works: ===
!==
==
The production formula
be the result of calculating
EqualityExpression : EqualityExpression == RelationalExpression
Let.
works:- .
lref
LetEqualityExpression
be- .
lval
LetGetValue(lref)
be the result of calculating- .
rref
LetRelationalExpression
berval
Returns the result of performing an abstract equality comparisonGetValue(rref)
. (See 11.9.3.)- Section 11.9.2 provides similar information on how
rval == lval
!=
The production formula
- Let
lref
be the result of calculatingEqualityExpression
.- Let
lval
beGetValue(lref)
.- Let
rref
be the result of calculatingRelationalExpression
.- Let
rval
beGetValue(rref)
.- Let
r
be the result of performing abstract equality comparisonrval != lval
. (See 11.9.3.)- If
r
istrue
, returnfalse
. Otherwise, returntrue
.
lref
and rref
are references on the left and right sides of the ==
and !=
operators. Each reference is passed to the GetValue()
internal function to return the corresponding value. The core of how ==
and !=
work is specified by the abstract equality comparison algorithm, given in Section 11.9.3:
Compare
x == y
, wherex
andy
are values, resulting intrue
orfalse
. This comparison is carried out as follows:
- If
Type(x)
is the same asType(y)
, then
- If
Type(x)
isUndefined
, returntrue
.- If
Type(x)
isNull
, returntrue
.- If
Type(x)
isNumber
, then
- If
x
isNaN
, returnfalse
.- If
y
isNaN
, returnfalse
.- If
x
andy
are the same numerical value, returntrue
.- If
x
is 0 andy
is -0, returntrue
.- If
x
is -0 andy
is 0, thentrue
will be returned.- Return
false
.- If
Type(x)
isString
, ifx
andy
are exactly the same character sequence (the same length and the same characters in the corresponding position), thentrue
is returned. Otherwise, returnfalse
.- If
Type(x)
isBoolean
, then ifx
andy
are bothtrue
or are bothfalse
, then returntrue
. Otherwise, returnfalse
.- If
x
andy
refer to the same object, returntrue
. Otherwise, returnfalse
.- If
x
isnull
andy
isundefined
, then returntrue
.- If
x
isundefined
andy
isnull
, then returntrue
.- If
Type(x)
isNumber
andType(y)
isString
, the result of comparisonx == ToNumber(y)
is returned.- If
Type(x)
isString
andType(y)
isNumber
, the result of comparisonToNumber(x) == y
is returned.- If
Type(x)
isBoolean
, the result of comparisonToNumber(x) == y
is returned.- If
Type(y)
isBoolean
, the result of comparisonx == ToNumber(y)
is returned.- If
Type(x)
isString
orNumber
andType(y)
isObject
, the result of comparisonx == ToPrimitive(y)
is returned.- If
Type(x)
isObject
andType(y)
isString
orNumber
, the result of comparisonToPrimitive(x) == y
is returned.- Return
false
.
Step 1 The operand type is the same when executed in this algorithm. It shows that undefined
is equal to undefined
, and null
is equal to null
.It also shows that nothing equals NaN
(non-number), two identical values are equal, 0 equals -0, two strings with the same length and sequence of characters are equal, true
equals true
, false
is equal to false
, and two references to the same object are equal. Steps 2 and 3 show why null != undefined
returns false
. JavaScript considers these values to be the same. Starting from step 4, the algorithm becomes interesting. This step focuses on the equality between the Number
and String
values. When the first operand is Number
and the second operand is String
, the second operand is converted to ToNumber()
through the internal function of Number
. The expression x == ToNumber(y)
means recursion; the algorithm starting from Section 11.9.1 is reapplied. Step 5 is equivalent to Step 4, but the first operand has a type String
and must be converted to a type Number
. Steps 6 and 7 convert the Boolean operand to a Number
type and recursively. If the other operand is a boolean, it will be converted to Number
the next time this algorithm is executed, which will recurse again. From a performance point of view, you may want to make sure both operands are boolean types to avoid two recursive steps. Step 9 shows that if the type of any operand is Object
, the operand is converted to the original value through the ToPrimitive()
internal function, and the algorithm recursively. Finally, the algorithm considers that the two operands are not equal and returns false
in step 10. Although detailed, the abstract equality comparison algorithm is quite easy to understand. However, it references a pair of internal functions ToNumber()
and ToPrimitive()
, whose internal work needs to be exposed to fully understand the algorithm. The ToNumber()
function converts its parameters to Number
and is described in Section 9.3. The following list summarizes possible non-numeric parameters and equivalent return values:
- If the parameter is
Undefined
, returnNaN
. - If the parameter is
Null
, return 0. - If the parameter is a Boolean value
true
, return 1. If the parameter is a Boolean valuefalse
, return 0. - If the parameter type is
Number
, the input parameter is returned - no conversion. - If the type of the parameter is
String
, then Section 9.3.1 “ToNumber of string type” is applied. Returns the value corresponding to the string parameter indicated by the syntax. If the parameter does not match the indicated syntax, returnNaN
. For example, the parameter "xyz" causes the returnNaN
. Furthermore, parameter "29" results in a return of 29. - If the type of parameter is
Object
, apply the following steps:- Let
primValue
beToPrimitive(输入参数, 提示Number)
. - Return
ToNumber(primValue)
.
- Let
ToPrimitive()
function accepts an input parameter and an optional PreferredType
parameter. The input parameters are converted to non-object type. If the object can be converted to multiple primitive types, ToPrimitive()
use the optional PreferredType
prompt to bias the preferred type. The conversion is carried out as follows:
- If the input parameter is
Undefined
, the input parameter (Undefined
) is returned - no conversion. - If the input parameter is
Null
, the input parameter (Null
) is returned - no conversion. - If the type of input parameter is
Boolean
, return the input parameter - no conversion. - If the type of input parameter is
Number
, return the input parameter - no conversion. - If the type of input parameter is
String
, return the input parameter - no conversion. - If the type of the input parameter is
Object
, the default value corresponding to the input parameter is returned. Retrieve the default value of the object by calling the object's[[DefaultValue]]
internal method and passing an optionalPreferredType
prompt. The behavior of[[DefaultValue]]
is defined in Section 8.12.8 for all native ECMAScript objects.
This section introduces quite a lot of theories. In the next section, we will turn to practice by providing various expressions involving ==
and !=
and gradually completing algorithmic steps.
Understand the Evil Twins
Now that we have understood how ==
and !=
work according to the ECMAScript specification, let us take advantage of this knowledge by exploring the various expressions involving these operators. We will walk through how to evaluate these expressions and find out why they are true
or false
. For my first example, consider the following expression pairs introduced near the beginning of the article:
"this_is_true" == false // false "this_is_true" == true // false
Follow the abstract equality comparison algorithm to evaluate these expressions according to the following steps:
- Skip step 1 because the types are different:
typeof "this_is_true"
returns "string", whiletypeof false
ortypeof true
returns "boolean". - Skip steps 2 to 6 that are not applicable because they do not match the operand type. However, step 7 applies because the right parameter has a type
Boolean
. The expression is converted to"this_is_true" == ToNumber(false)
and"this_is_true" == ToNumber(true)
. -
ToNumber(false)
returns 0,ToNumber(true)
returns 1, which simplifies the expressions to"this_is_true" == 0
and"this_is_true" == 1
respectively. At this time the algorithm recursively. - Skip steps 1 to 4 that are not applicable because they do not match the operand type. However, step 5 applies because the type of the left operand is
String
and the type of the right operand isNumber
. The expression is converted toToNumber("this_is_true") == 0
andToNumber("this_is_true") == 1
. -
ToNumber("this_is_true")
ReturnsNaN
, which simplifies the expressions toNaN == 0
andNaN == 1
respectively. At this time the algorithm recursively. - Go to step 1, because the types of
NaN
, 0 and 1 are allNumber
. Skip steps 1.a and 1.b that are not applicable. However, step 1.c.i applies because the left operand isNaN
. The algorithm now returnsfalse
(NaN
is not equal to anything, including itself) as the value of each original expression and backtracks the stack to exit recursion completely.
My second example (based on the explanation of the meaning of life in the "Galaxy Wandering Guide") compares an object with a number by ==
and returns true
:
"this_is_true" == false // false "this_is_true" == true // false
The following steps show how JavaScript uses the abstract equality comparison algorithm to get true
as the value of the expression:
- Skip steps 1 to 8 that are not applicable because they do not match the operand type. However, step 9 applies because the type of the left operand is
Object
and the type of the right operand isNumber
. The expression is converted toToPrimitive(lifeAnswer) == 42
. -
ToPrimitive()
Call thelifeAnswer
Internal method of[[DefaultValue]]
, without prompt. According to Section 8.12.8 of the ECMAScript 262 specification, the[[DefaultValue]]
calls thetoString()
method, which returns "42". The expression is converted to"42" == 42
, and the algorithm is recursive. - Skip steps 1 to 4 that are not applicable because they do not match the operand type. However, step 5 applies because the type of the left operand is
String
and the type of the right operand isNumber
. The expression is converted toToNumber("42") == 42
. -
ToNumber("42")
Returns 42, and the expression is converted to42 == 42
. The algorithm recurses and executes step 1.c.iii. Because the numbers are the same,true
is returned and expanded recursively.
For my last example, let's find out why the following sequence does not show transitiveness, where the third comparison will return true
instead of false
:
"this_is_true" == false // false "this_is_true" == true // false
The following steps show how JavaScript uses the abstract equality comparison algorithm to get true
as the value of '' == 0
.
- Execute step 5, resulting in
ToNumber('') == 0
, which is converted to0 == 0
, and the algorithm recursively. (Section 9.3.1 of the specification states that StringNumericLiteral::: [empty]'s MV [mathematical value] is 0. In other words, the value of an empty string is 0.) - Execute step 1.c.iii, which compares 0 with 0 and returns
true
(and expands recursion).
The following steps show how JavaScript uses the abstract equality comparison algorithm to get true
as the value of 0 == '0'
:
- Execute step 4, resulting in
0 == ToNumber('0')
, which is converted to0 == 0
, and the algorithm recursively. - Execute step 1.c.iii, which compares 0 with 0 and returns
true
(and expands recursion).
Finally, JavaScript performs step 1.d in the abstract equality comparison algorithm to obtain true
as the value of '' == '0'
. Because the two strings have different lengths (0 and 1), return false
.
Conclusion
You may be wondering why you should bother using ==
and !=
. After all, previous examples have shown that these operators may be slower than the ===
and !==
operators due to type casting and recursion. You may want to use ==
and !=
because in some cases there are no advantages. Consider the following example: ===
"this_is_true" == false // false "this_is_true" == true // falseThe
typeof
operator returns a String
value. Because the String
value is compared to another String
value ("object"), no type casting occurs, and ==
is as efficient as ===
. Maybe a JavaScript newbie who has never encountered ===
will find such code clearer. Similarly, the following code snippet does not require type casting (the types of both operands are Number
), so !=
is as efficient as !==
:
'' == 0 // true 0 == '0' // true '' == '0' // false
These examples show that ==
and !=
are suitable for comparisons that do not require casting. When operand types are different, ===
and !==
are the best choices because they return false
rather than unexpected values (e.g. false == ""
returns true
). If the operand type is the same, there is no reason not to use ==
and !=
. Maybe it's time to stop being afraid of evil twins, and once you understand them, they're less evil.
FAQs for JavaScript Equality and Comparison Operators (FAQs)
What is the difference between
==
and ===
in JavaScript?
In JavaScript, ==
and ===
are comparison operators. However, they differ in the way they compare values. The ==
operator (also known as the loose equality operator) performs type casting before comparison. This means that if you compare two different types of values, JavaScript will try to convert one type to another before performing the comparison. On the other hand, the ===
operator (called the strict equality operator) does not perform type casting. It compares values and types at the same time, which means that if the two value types are different, JavaScript will consider them to be unequal.
Why should I use ===
instead of ==
in JavaScript?
is generally recommended to use ===
instead of ==
in JavaScript, because it provides stricter comparisons, which means it does not perform type casts and checks for values and types. This can help avoid unexpected results when comparing different types of values. For example, when using ==
, JavaScript considers the number 0 and the empty string "" equal, because it converts the type before comparison. However, using ===
, they will be considered unequal because they are of different types.
What is type cast in JavaScript?
Type cast in JavaScript refers to automatically or implicitly converting values from one data type to another. This happens when operators are used for different types of operands or when some type is required. For example, when using the loose equality operator (==
), JavaScript will try to convert operands to general types before making comparisons.
How does JavaScript handle object comparison?
In JavaScript, objects are compared by reference, not by value. This means that even if two objects have exactly the same properties and values, they are not considered equal because they refer to different objects in memory. The only case where objects are considered equal is that they refer to exactly the same object.
What is the difference between
==
and !=
in JavaScript?
==
and !=
are comparison operators in JavaScript. The ==
operator checks whether the values of the two operands are equal, and performs type casts if necessary. On the other hand, the !=
operator checks whether the values of the two operands are not equal, and performs type casts if necessary.
===
and !==
in JavaScript?
===
and !==
are comparison operators in JavaScript. The ===
operator checks whether the values of the two operands are equal, taking into account both the values and types. On the other hand, the !==
operator checks whether the values of the two operands are not equal, taking into account both the values and types.
How to compare two arrays in JavaScript?
In JavaScript, arrays are objects, compared by reference, not by value. This means that even if two arrays contain the same elements in the same order, they are not considered equal because they refer to different objects in memory. To compare two arrays by their content, you need to compare each element separately.
How does JavaScript handle the comparison between null
and undefined
?
In JavaScript, null
and undefined
are considered loosely equal (==
) because they both represent missing values. However, they are not strictly equal (===
) because they are of different types.
What is the priority order of comparison operators in JavaScript?
In JavaScript, comparison operators have the same priority level. They are calculated from left to right. However, it is important to note that they have lower priority than arithmetic and bitwise operators, but higher than logical operators.
Can I use comparison operators with strings in JavaScript?
Yes, you can use comparison operators with strings in JavaScript. JavaScript uses lexical (dictionary) order when comparing strings. However, it is important to note that capital letters are considered "small" than lowercase letters because they have smaller ASCII values.
The above is the detailed content of Don't Fear the Evil Twins - SitePoint. For more information, please follow other related articles on the PHP Chinese website!

Understanding how JavaScript engine works internally is important to developers because it helps write more efficient code and understand performance bottlenecks and optimization strategies. 1) The engine's workflow includes three stages: parsing, compiling and execution; 2) During the execution process, the engine will perform dynamic optimization, such as inline cache and hidden classes; 3) Best practices include avoiding global variables, optimizing loops, using const and lets, and avoiding excessive use of closures.

Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

Python and JavaScript have their own advantages and disadvantages in terms of community, libraries and resources. 1) The Python community is friendly and suitable for beginners, but the front-end development resources are not as rich as JavaScript. 2) Python is powerful in data science and machine learning libraries, while JavaScript is better in front-end development libraries and frameworks. 3) Both have rich learning resources, but Python is suitable for starting with official documents, while JavaScript is better with MDNWebDocs. The choice should be based on project needs and personal interests.

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

JavaScript's applications in the real world include server-side programming, mobile application development and Internet of Things control: 1. Server-side programming is realized through Node.js, suitable for high concurrent request processing. 2. Mobile application development is carried out through ReactNative and supports cross-platform deployment. 3. Used for IoT device control through Johnny-Five library, suitable for hardware interaction.

I built a functional multi-tenant SaaS application (an EdTech app) with your everyday tech tool and you can do the same. First, what’s a multi-tenant SaaS application? Multi-tenant SaaS applications let you serve multiple customers from a sing

This article demonstrates frontend integration with a backend secured by Permit, building a functional EdTech SaaS application using Next.js. The frontend fetches user permissions to control UI visibility and ensures API requests adhere to role-base


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

SublimeText3 English version
Recommended: Win version, supports code prompts!

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

MinGW - Minimalist GNU for Windows
This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

SublimeText3 Chinese version
Chinese version, very easy to use

SublimeText3 Mac version
God-level code editing software (SublimeText3)