WasiLearn Code
JavaScript · Making decisions and repeating

== versus ===, the famous one

A student types their age into a form. You want to check whether they are 18. You have two equality operators available, they look almost the same, and they give opposite answers.

let typedAge = "18";

console.log(typedAge == 18);
console.log(typedAge === 18);
output
true
false

Neither one is broken. They are asking different questions, and knowing which question you actually meant is the difference between a form that works and a form that lets a fifteen-year-old through.

=== asks one question, == asks two

=== is strict equality. It asks: are these the same type, and the same value? If the types differ, the answer is false immediately — no conversion, no negotiation.

console.log(75 === 75);
console.log("Karachi" === "Karachi");
console.log(true === true);
console.log(75 === "75");
console.log(75 !== "75");
output
true
true
true
false
true

!== is the opposite: are these different in type or value?

== is loose equality. If the two sides are already the same type it behaves exactly like ===. If they are not, it converts one side to match the other and then compares. That conversion is called type coercion, and it follows rules nobody has memorised on purpose.

console.log("7" == 7);
console.log(0 == false);
console.log(1 == true);
console.log("" == 0);
console.log(null == undefined);
console.log(null == 0);
output
true
true
true
true
true
false

Look at the last two together. null is loosely equal to undefined, which is reasonable — both mean nothing, as the data types lesson describes. But null is not loosely equal to 0, even though false is. There is no principle you can derive that from. It is a list of special cases in the specification.

The comparison operators

>, <, >= and <= behave the way school algebra taught you, and each returns a boolean.

let busSeats = 42;

console.log(busSeats > 40);
console.log(busSeats >= 42);
console.log(busSeats < 42);
console.log(busSeats <= 42);
output
true
true
false
true

Unlike ===, these four have no strict version. They always coerce. That is worth remembering, because it is where the next trap lives.

Comparing strings is not comparing numbers

console.log("10" > "9");
console.log(10 > 9);
console.log("10" > 9);
console.log("Ayesha" < "Bilal");
console.log("apple" < "Apple");
output
false
true
true
true
false

The first line is the one to stare at. With strings on both sides, JavaScript compares them character by character, like a dictionary. "1" comes before "9", so "10" sorts before "9" and the comparison is false.

The third line has one number, so both sides become numbers and you get the arithmetic answer. Same operator, same-looking values, opposite results, decided entirely by whether you remembered to strip the quotes.

The last line shows that sorting is by character code, not by the alphabet as people think of it. Every capital letter comes before every small one, which is why "apple" < "Apple" is false. Lowercase both sides before comparing names, using the method from the strings lesson.

Why beginners reach for ==, and what it costs

The honest reason == gets used is that it is one character shorter, it works in most of the cases a beginner tries, and typing three equals signs feels like superstition. So you write ==, everything passes, and you conclude the strict version is pedantry.

Then a real value arrives. Something is 0 when you expected false, or an empty string when you expected a missing value, and == cheerfully declares two unrelated things equal. Now you are debugging a comparison that looks correct on the screen.

The specification's conversion rules run to several pages. They involve converting objects to primitives, then strings to numbers, with different orders depending on which types are involved. Experienced developers do not have them memorised either. They just do not use ==, so they never need to.

The rule is short: use === and !== everywhere. When the two sides are different types, that is a fact you want to know about, not one you want silently smoothed over. Convert deliberately with Number or String, then compare strictly, and every comparison in your program means what it says.

The famous one: [] == false

The example that gets shown whenever people argue about JavaScript uses an empty array — a list with nothing in it, which you will meet properly in the arrays lesson.

console.log([] == false);
console.log([] == "");
console.log([] == 0);
console.log([] == "0");
output
true
true
true
false

An empty array is equal to false, equal to an empty string, equal to zero, and not equal to "0". Traced through the rules it is consistent: the array is converted to a primitive, which gives the empty string ""; false becomes the number 0; "" also becomes 0; and 0 == 0 is true. The last line stays a string-to-string comparison, and "" is not "0".

Every step is legal. The result is still absurd. That is the point — the coercion rules do not produce nonsense because they are broken, they produce nonsense because they are applied faithfully to values that should never have been compared in the first place. === refuses at the first step, which is the behaviour you want.

The one place == earns its keep

There is a single idiom where experienced developers use == deliberately. x == null is true for exactly two values — null and undefined — and false for everything else.

let middleName = null;
let nickname;

console.log(middleName == null);
console.log(nickname == null);
console.log(0 == null);
console.log("" == null);
output
true
true
false
false

That is genuinely useful for "is there no value here, by either route?" without writing the check twice. It is safe because that particular rule is narrow and easy to remember. It is also the only exception, and if you would rather write middleName === null || middleName === undefined, nobody will complain.

NaN is not equal to anything, including itself

console.log(NaN == NaN);
console.log(NaN === NaN);
output
false
false

Neither operator helps here, so no amount of switching between them will detect a failed calculation. Number.isNaN is the tool, and the numbers lesson covers why.

Convert first, then compare strictly

The pattern that makes the whole problem disappear: turn the incoming text into the type you actually mean, in a named variable, then compare with ===.

let enteredMarks = "88";
let marks = Number(enteredMarks);

console.log(marks === 88);
console.log(enteredMarks === 88);
console.log(marks > 80);
output
true
false
true

Two lines instead of one, and the conversion is visible to anyone reading the code — including you in six months. Every comparison after that line is comparing numbers to numbers, which is the only kind of comparison that never surprises you. Those booleans are about to become useful in the if and else lesson.

Prefer learning with a teacher?

WasiLearn Academy runs small-group classes covering this material, online and in Karachi.

See the classes