A deep and pragmatic guide to the <, >, <= and >= comparison operators of JavaScript

These four operators as you might have guessed are used for comparing values in JavaScript. The names of these operators are:

>Less than
>Greater than
<=Less than or equal
>=Greater than or equal

They are part of a set of operators known as comparison operators. There are other comparison operators too(e.g. ==, ===, != and !==) but they are not today's topic.

These operators are also part of a set of operators officially known as relational operators. Note that there are two relational operators (in and instanceof) that are not comparison operators.

To only refer to these four operators there is a precise term also: ordering operators. They are called ordering operators because they allow you to know the comparative position of two values. However this is very less known term and people might not immediately understand what you are talking about.

In this article we dig deep but in a pragmatic way into these four comparison operators.

Table of contents

The less than operator: <

The art of knowing is knowing what to ignore. - Rumi

JavaScript attempts to compare any value you give to these operators. And there are lots of rules going on make that happen. Luckily we can ignore most of them if strange comparisons like comparing arrays to numbers or objects etc. are something not important to you or your team members.

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).

Comparing Number and BigInt types of values

Comparing Numbers

These are mostly as in mathematics. For example:

4 < 6  // true
10 < 9 // false

As values Number type have a limited precision, for very big numbers literals or numbers literals with a lots of digits after the decimal point, 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 return false.
  • If leftNumber is the same number as rightNumber, return false.
  • If leftNumber is Infinity, return false.
  • If rightNumber is Infinity, return true.
  • If leftNumber is -Infinity, return true.
  • If rightNumber is -Infinity, return false.
  • If leftNumber is less than rightNumber as in mathematics, return true. Otherwise return false.

Comparing BigInt

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 ordering for comparing string values which can become handy when we know how it works and we don't need any advanced comparison.

Info: The heavy phrase "Lexicographic ordering" means nothing other than any ordering similar to the alphabetic ordering of the dictionaries.

A brief tour to Unicode

To understand string comparison, it's important to understand how JavaScript strings are made of.

For the dumb computers to make sense of JavaScript strings, they must be encoded in some way. JavaScript does it using UTF-16.

What is UTF-16? It stands for 16-bit Unicode Transformation Format. But what's that mean? It means a string in JavaScript is a sequence of 16 bit code units. You might be asking what's a code unit?

Well a code unit is a number to encode a code point. What is a code point? A codepoint is also a number composed of a single 16 bit code unit or two 16 bit code units. Each character is encoded as one or more codepoints in unicode.

A string gets an index at each code unit holding a part of the string. Let's call each such this part a string element(this is not a unicode term).

The concept of character is hard to define. For simplicity we can define it like below:

  • Any symbol that doesn't seems broken.
  • The invisible things that allows you to do space, tabs and newlines.

We can write a function to get the decimal values of the code units of a string:

function getCodeUnits(s) {
  let result = [];
  for (let i = 0; i < s.length; i++) {
  return result;

getCodeUnits("Hi 😄");
// [72, 105, 32, 55357, 56836]

getCodeUnits("I ❤️‍🔥 JS");
// [73, 32, 10084, 65039, 8205, 55357, 56613, 32, 74, 83]

Note that the 😄 emoji needs 2 code units and the ❤️‍🔥 needs 5 code units.

The string comparison algorithm

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 with rightString, return false. For example:

    'hello world' < 'hello'
    // false
    'hello world' < ''      
    // false, because every string starts with an empty string
  • If rightString starts with leftString, return true. 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 units of the string element of the two strings are different. Let s be that index. In the following example s is 4:

    'Linux' < 'Linus Torvalds'
    // [76, 105, 110, 117, 120]
    getCodeUnits('Linus Torvalds');
    // [76, 105, 110, 117, 115, 32, 
    // 84, 111, 114, 118, 97, 108, 100, 115]
  • Let m be leftString.charCodeAt(s).

  • Let n be rightString.charCodeAt(s).

  • If m < n return true, otherwise return false.

    For the example at step 3, m is 120 and n is 115, so 'Linux' < 'Linus Torvalds' is false!

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.

Luckily JavaScript now allows proper language aware comparison through the awesome Intl.Collator object, which is beyond the scope of this article.

The other ones: >, <= and >=

They behave the same as their name suggests and you may stop reading further this article if you wish. But if you are curious, you are welcome 🤗

For these operators, here we again limit ourselves in the following ways:

  • We will only deal with values of types Number, BigInt and String.
  • Both operands will have the same type.
📝Note: JavaScript always ensures left to right evaluation of expressions. So inside the algorithms below the leftValue might go to the right and vice versa but the expressions that forms those values are always evaluated left to right.

You don't need to remember or memorize these algorithms as you can easily predict their behaviors by their names. This is just for understanding their behavior in a deeper way.

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 rightValue < leftValue

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.
  • If rightValue < leftValue is true
    • Return false
  • Else
    • Return true

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.
  • If leftValue < rightValue is true
    • Return false
  • Else
    • Return true

If you found this article helpful, please buy me a coffee