Equality, type coercion and what this points to
Predict == versus ===, truthy and falsy values, the ?? operator, and why a method loses this when you pass it around.
"What does this print?" questions in JavaScript screenings almost always come from two areas: the loose equality rules and the value of this. Both have fixed rules you can learn in an hour, and both cause real bugs in the first month on a job.
Loose and strict equality
=== compares type and value with no conversion. == converts operands first, which produces results that look random until you know the rules: strings become numbers, booleans become numbers, and null equals only undefined.
console.log(0 == ""); // true
console.log(0 === ""); // false
console.log(null == undefined); // true
console.log("5" + 3); // "53" (+ with a string joins)
console.log("5" - 3); // 2 (- always converts to numbers)Use === everywhere. The one accepted use of == is x == null to catch both null and undefined.
Truthy, falsy and defaults
Exactly these values are falsy: false, 0, "", null, undefined and NaN. Everything else is truthy, including "0", [] and {}.
const count = 0;
console.log(count || 10); // 10 (0 is falsy, so the fallback wins)
console.log(count ?? 10); // 0 (?? only replaces null or undefined)This is why ?? is the right operator for default values when zero or an empty string is a valid input.
What this refers to
In a normal function, this is decided by how the function is called, not where it was written. Called as obj.method(), it is obj. Called on its own, it is undefined in strict mode and modules, or the global object in sloppy scripts. Arrow functions have no this of their own; they use the one from the surrounding code.
const user = { name: "Asha", greet() { return "Hi " + this.name; } };
console.log(user.greet()); // Hi Asha
const greet = user.greet;
console.log(greet()); // "Hi undefined", or a TypeError in strict mode
console.log(user.greet.bind(user)()); // Hi Asha
const timer = {
name: "T",
start() {
setTimeout(() => console.log(this.name), 0); // T
setTimeout(function () { console.log(this.name); }, 0); // undefined
}
};
timer.start();The arrow inside start keeps the object's this; the plain function gets a fresh one. bind fixes this permanently; call and apply set it for one call.
Common mistakes and a practice habit
- Checking
x === NaN. It is always false; useNumber.isNaN. - Using
||for a default and silently replacing a legitimate zero. - Passing
obj.methodas a callback and losingthis. Pass() => obj.method()or bind it. - Using an arrow function as an object method and expecting
thisto be the object.
Practice habit: Keep a scratch file open in Node and, whenever a comparison or a callback surprises you, reduce it to three lines and run it. Collect those snippets. Re-reading them the night before a screening is better preparation than any list of rules.
More in Programming