Skip to main content

Command Palette

Search for a command to run...

JavaScript Quirks That Will Make You Say “Wait, What?”

Strange-looking JavaScript behaviors explained with simple examples and the rules behind them.

Updated
7 min readView as Markdown
JavaScript Quirks That Will Make You Say “Wait, What?”
M
Software Developer

Question - 1

console.log(null === undefined) //false

Why it's false.👀

  • Expression*:* null === undefined

  • Result*:* false

Explanation

In JavaScript, both null and undefined represent "empty" values but are distinct (different) types.

null is a special object representing the intentional absence of a value, while undefined signifies that a variable has been declared but not assigned a value.

Despite their similar purpose, they are not strictly equal (===) to each other.

  • null === undefined evaluates to false because JavaScript does not perform type coercion with ===.

Question - 2

console.log(5 > 3 > 2) //false

Why it's false.👀

  • Expression*:* 5 > 3 > 2

  • Result*:* false

Explanation

At first glance, this expression may appear to be checking if 5 is greater than 3 and 3 is greater than 2, but JavaScript evaluates it left-to-right due to its operator precedence.

  • First, 5 > 3 evaluates to true.

  • Then, true > 2 is evaluated, which in JavaScript results in 1 > 2 (since true is coerced to 1), which evaluates to false.

So, 5 > 3 > 2 evaluates to false.

Question - 3

console.log([] === []) //false

Why it's false.👀

  • Expression*:* [] === []

  • Result*:* false

Explanation

In JavaScript, arrays are objects. Even if two arrays have the same content, they are still different objects in memory.

  • When you compare two arrays with ===, you are comparing their references, not their contents.

  • Since [] and [] are different instances in memory, so the result is false.

Question - 4

console.log("10" < "9"); //true

Why it's true.👀

  • Expression*:* "10" < "9"

  • Result*:* true

Explanation

When JavaScript compares strings, it compares their Unicode values lexicographically (character by character).

  • "10" is compared to "9". Since "1" has a lower Unicode value than "9", JavaScript determines that "10" is less than "9".

  • This comparison might seem counterintuitive, but it's due to JavaScript's string comparison mechanism.

Question - 5

console.log(NaN === NaN);

Why it's false.👀

  • Expression*:* NaN === NaN

  • Result*:* false

Explanation

In JavaScript, NaN (Not-a-Number)is a special value that represents an invalid number or the result of an operation that cannot produce a valid number.

  • One of the most unusual aspects of NaN is that it is not equal to itself. This behavior exists due to the design of the IEEE 754 standard, which JavaScript follows for floating-point arithmetic.

  • As a result, NaN === NaN returns false.

To check if a value is NaN, use Number.isNaN().

Question-6

console.log(true == 1);

Why it's true.👀

  • Expression: true == 1

  • Result: true

Explanation

JavaScript uses type coercion with the loose equality operator (==). When comparing true and 1, JavaScript converts true to 1 and then compares the values.

  • Since 1 == 1 is true, the overall expression evaluates to true.

This behavior might lead to unexpected results in some cases, so it’s often recommended to use the strict equality operator (===) to avoid implicit type coercion.

Question-7

console.log(undefined > 0);

Why it's false.👀

  • Expression: undefined > 0

  • Result: false

Explanation

When JavaScript attempts to compare undefined with 0, it converts undefined to NaN (Not-a-Number). Any comparison involving NaN returns false.

  • undefined > 0 becomes NaN > 0, which evaluates to false.

Question-8

console.log("5" === 5);

Why it's false.👀

  • Expression: "5" === 5

  • Result: false

Explanation

The strict equality operator (===) checks both value and type. Since "5" is a string and 5 is a number, the types are different, and the comparison returns false.

  • If you used the loose equality operator (==), JavaScript would perform type coercion, converting the string "5" to the number 5, and the comparison would return true.

Question-9

console.log([1, 2] == [1, 2]);

Why it's false.👀

  • Expression: [1, 2] == [1, 2]

  • Result: false

Explanation

Even though both arrays contain the same elements, JavaScript compares arrays by reference, not by value.

  • Since each array is a separate object in memory, their references are different, and thus the comparison returns false.

To check if two arrays are equal, you must compare their contents element by element.

Question-10

console.log(Infinity > 1000);

Why it's true.👀

  • Expression: Infinity > 1000

  • Result: true

Explanation

In JavaScript, Infinity represents an unbounded, positive number. It's greater than any finite number, including 1000.

  • Therefore, Infinity > 1000 evaluates to true.

IEEE Standard 754 floating-points numbers

It's a technical and official standard used by computers to store and do math with real (decimal) numbers.

Every IEEE 754 floating-point number splits memory into three parts:

  • Sign Bit: Tells you if the number is positive (0) or negative (1). Zero (0) represents a positive number while one (1) represents a negative number.

  • Biased Exponent: Stores the power of two. A fixed bias number is added to the actual exponent so negative and positive powers can both be saved as unsigned bit values.

  • Normalized Mantissa (Significand): Stores the actual significant digits. Most formats assume an invisible leading 1 before the binary point to save space.

IEEE 754 numbers standard defines several sizes based on the above three components.

Half-Precision, Single precision, Double precision, and Quadruple-Precision.

Single Precision

Double Precision

  • Half-Precision (16-bit / binary16): 1 sign bit, 5 exponent bits (bias 15), 10 mantissa bits.

  • Single-Precision (32-bit / binary32): 1 sign bit, 8 exponent bits (bias 127), 23 mantissa bits. Gives about 7 decimal digits of precision.

  • Double-Precision (64-bit / binary64): 1 sign bit, 11 exponent bits (bias 1023), 52 mantissa bits. Gives about 16 decimal digits of precision.

  • Quadruple-Precision (128-bit / binary128): 1 sign bit, 15 exponent bits (bias 16383), 112 mantissa bits.

Precision

To demonstrate how this representation works, let us take the value 9.1, a single-precision value. To convert this number to IEEE 754 standard, we have to follow the below steps.

  1. Convert the floating-point number into binary.

  2. Write the converted binary in scientific format*.*

  3. Write the binary (which is written in scientific format) according to IEEE 754 standard.

A the end, 9.1 will be converted to a binary with a sign bit, exponent, and a mantissa.

1. Convert the floating-point number into binary.

Let us first convert 9.1 into binary. When converting it into binary, we need to identify 9 as an integral part, and 0.1 as the fractional part which should be converted separately.

So when converted 9.1 to binary we get 1001.000110011001100

Even though 9.1 is an infinite binary number*, we have only* 23 bits to store it.

2. Write the converted binary in scientific format.

When written 9.1 in scientific notation, the following is the result.

1.001000110011001100... x 2^3

3. Write the binary (which is written in scientific format) according to IEEE 754 standard.

Next, this number should be written in IEEE 754 format.

The first bit in IEEE 754 Floating-point standard is the signed bit.

Special Values

The standard also reserves bit patterns for special conditions:

  • Infinity (±∞): Results from overflow or dividing a positive number by zero.

  • NaN (Not a Number): Results from invalid operations like 0/0.

  • Signed Zeros: Both positive (+0) and negative (-0) zero exist.

  • Subnormal (De-normalized) Numbers: Tiny numbers close to zero (0) that lose precision to prevent abrupt underflow.

💡
JavaScript isn’t random, it’s following rules. Once you understand those rules, the weird behavior stops being weird.

JavaScript from scratch to advance

Part 1 of 5

A practical, beginner-friendly series covering JavaScript fundamentals from the basics to advanced concepts, with clear explanations, examples, and real-world use cases.

Up next

JavaScript Fundamentals: The Concepts Beginners Often Miss

Understand the JavaScript concepts that seem simple until they behave unexpectedly.