Deep dive into <
, >
, <=
and >=
operators of JavaScript
Operator | Name |
---|---|
< | Less than |
> | Greater than |
<= | Less than or equal |
>= | Greater than or equal |
You have propbably used these operators countless times to compare numbers in your programming journey with JavaScript without any problems.
But did you know that JavaScript can compare not only numbers but also all kinds of values? While this may seem strange, it has some useful use cases, especially when comparing ASCIIrefs:asciiunicode strings of same case. While exploring these comparisons, I found the process of comparing numbers, strings and how the operators >
, <=
, >=
derived from <, to be quite interesting. In this article, I will share with you everything that If found useful or interesting while exploring these operators. Let's start.
They are part of a set of operators known as comparison operators.refs:compopsnotes:othercompops These operators are also part of a set of operators officially known as relational operators.refs:relopsnotes:otherrelops
To make life simple and easy, here I will ignore all the less useful comparisons and only go into the depth of the most useful ones:
- I will only write about the comparisons of Number, BigInt and String types.
- I will ignore the cases where the types of the operands differ(I think it's better to explicitly convert values to the same type before comparing them to make things clear).
The less than operator(<
)
This is a crucial operator because the other three operators(>
, <=
and >=
) are based on it. So I will go into its depth as much as I find worthwhile and then will see how easy it to learn about the inner workings of the other three operators.
Comparing Numbers
These are mostly as in mathematics. For example:
4 < 6; // true
10 < 9; // false
As values Number type have a limited precisionrefs:numprecision, for very long numbers literals you might get incorrect result when comparing them. For example:
3 < 3.00000000000000001; // false
88888888888888888 < 88888888888888889; // false
This is because these numbers loose some precision when they are turned into values from literals.
For comparing leftNumber < rightNumber
where leftNumber
and rightNumber
are values(not literals!) of Number type, the following algorithm is used:
- If either value is
NaN
returnfalse
. - If
leftNumber
is the same number asrightNumber
, returnfalse
. - If
leftNumber
isInfinity
, returnfalse
. - If
rightNumber
isInfinity
, returntrue
. - If
leftNumber
is-Infinity
, returntrue
. - If
rightNumber
is-Infinity
, returnfalse
. - If
leftNumber
is less thanrightNumber
as in mathematics, returntrue
. Otherwise returnfalse
.
Comparing BigInts
As BigInts don't have NaN or infinities, and they have arbitrary precision, they work just as fine as in mathematics.
88888888888888888n < 88888888888888889n; // true
Comparing Strings
<
operator uses a simple lexicographic orderingnotes:lex for comparing string values which can become handy when we know how it works and we don't need any advanced comparison.
Let leftString
and rightString
are strings and we want to know how JavaScript evaluates the value of the expression leftString < rightString
. Here goes the algorithm:
-
If
leftString
starts withrightString
, returnfalse
. For example:"hello world" < "hello"; // false "hello world" < ""; // false, because every string starts with an empty string
-
If
rightString
starts withleftString
, returntrue
. For example:"hello" < "hello world"; // true "" < "hello world"; // true
-
At this point, as neither string starts with the other, there must be a smallest index where code unitsrefs:codeunit of the two strings are different. Let
s
be that index. In the following examples
is4
:"Linux" < "Linus Torvalds"; getCodeUnits("Linux"); // [76, 105, 110, 117, 120] getCodeUnits("Linus Torvalds"); // [76, 105, 110, 117, 115, 32, // 84, 111, 114, 118, 97, 108, 100, 115]
See
getCodeUnits
implementationrefs:codeunitfunction getCodeUnits(s) { let result = []; for (let i = 0; i < s.length; i++) { result.push(s.charCodeAt(i)); } return result; }
-
Let
m
beleftString.charCodeAt(s)
.refs:charCodeAt -
Let
n
berightString.charCodeAt(s)
.refs:charCodeAt -
If
m < n
returntrue
, otherwise returnfalse
.For the example at step 3,
m
is120
andn
is115
, so'Linux' < 'Linus Torvalds'
isfalse
!
Note that comparison with <
is not like dictionaries in all cases, for example when lowercase, uppercase or accents are involved. But for simple comparisons like comparing two lowercase English letters or words, it works just fine because they fall under ASCII subset of Unicode.refs:asciiunicode
Luckily JavaScript now allows proper language aware comparison through the awesome Intl.Collator object. It is beyond the scope of this article.
Let's now see how the other three operators work.
Greater than operator: >
leftValue > rightValue
can be described as below:
- If both operands are of Number type and either one is
NaN
- Return
false
.
- Return
- Return
rightValue < leftValue
.notes:evalorder
Less than or equal operator: <=
leftValue <= rightValue
can be described as below:
- If both operands are of Number type and either one is
NaN
- Return
false
.
- Return
- If
rightValue < leftValue
istrue
notes:evalorder- Return
false
.
- Return
- Else
- Return
true
.
- Return
Greater than or equal operator: >=
leftValue >= rightValue
can be described as below:
- If both operands are of Number type and either one is
NaN
- Return
false
.
- Return
- If
leftValue < rightValue
istrue
- Return
false
.
- Return
- Else
- Return
true
.
- Return
Notes
- [othercompops] The other comparison operators
==
,===
,!=
and!==
. - [otherrelops] There are two relational operators that are not comparison operators:
in
andinstanceof
. - [lex] The heavy phrase "Lexicographic ordering" means an ordering similar to the alphabetic ordering of the dictionaries.
- [evalorder] JavaScript always evaluates expressions from left to write while reading its source code. Here though the
rightValue
appears to the left, it would not make it evalutate before theleftValue
becauseleftValue
appeared to the left in initial expresssion that this algorithm is about.
References
- [charCodeAt]
String.prototype.charCodeAt()
- MDN - [codeunit] How JavaScript strings are made?
- [compops] Comparison operators - MDN
- [relops] Relational Operators - ECMAScript Language Specification
- [numprecision] How numbers are encoded in JavaScript
- [asciiunicode] What's the difference between ASCII and Unicode?