HomebaseWorks
Lesson 3 of 4

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.

EWritten by the HomebaseWorks editorial team · reviewed 26 Oct 2026

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

Advertisement

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; use Number.isNaN.
  • Using || for a default and silently replacing a legitimate zero.
  • Passing obj.method as a callback and losing this. Pass () => obj.method() or bind it.
  • Using an arrow function as an object method and expecting this to 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.

Advertisement
Continue with JavaScript4 lessons · 1 interview set · 1 test · 1 certificate
Not tested

More in Programming