Difficulty: Intermediate
Explain type coercion in JavaScript. What are the rules for == vs === and truthy/falsy values?
Type coercion is JavaScript's automatic conversion of values from one type to another. It happens in two contexts: implicit coercion (triggered by operators and comparisons) and explicit coercion (using functions like Number(), String(), Boolean()).
The == operator performs type coercion before comparison, while === (strict equality) does not - it requires both value AND type to match. The == rules are complex: null == undefined is true, numbers are compared numerically, and objects are converted with valueOf/toString.
There are exactly 8 falsy values in JavaScript: false, 0, -0, 0n (BigInt zero), '' (empty string), null, undefined, and NaN. Everything else is truthy, including empty objects {}, empty arrays [], and the string 'false'.
Understanding coercion is essential because it causes many subtle bugs, especially with ==, + (concatenation vs addition), and if conditions.
// Strict equality - no coercion
console.log(1 === '1'); // false (different types)
console.log(1 === 1); // true
console.log(null === undefined); // false
// Loose equality - with coercion
console.log(1 == '1'); // true (string -> number)
console.log(true == 1); // true (boolean -> number)
console.log(null == undefined); // true (special rule)
console.log(null == 0); // false (null only == undefined)
console.log('' == false); // true (both -> 0)
// Surprising results
console.log([] == false); // true ([] -> '' -> 0, false -> 0)
console.log([] == ![]); // true ([] -> 0, ![] -> false -> 0)
console.log('' == 0); // true
console.log(' \t\n' == 0); // true (whitespace string -> 0)
== coerces types before comparing. The rules are: null == undefined, string/boolean convert to number, objects convert via valueOf/toString. Always use === to avoid surprises.
// All 8 falsy values
const falsyValues = [false, 0, -0, 0n, '', null, undefined, NaN];
falsyValues.forEach(val => {
console.log(`${String(val).padEnd(10)} -> ${Boolean(val)}`);
});
console.log('---');
// Common truthy surprises
const truthySurprises = ['0', 'false', [], {}, function(){}];
truthySurprises.forEach(val => {
console.log(`${String(val).padEnd(14)} -> ${Boolean(val)}`);
});
// Practical: checking for values
const port = 0;
if (port) console.log('has port'); // skipped! 0 is falsy
if (port !== undefined) console.log('port defined'); // correct
Only 8 values are falsy. Empty arrays, empty objects, and the string '0' are all truthy. Use explicit checks when 0 or '' are valid values.
// + with strings = concatenation
console.log('5' + 3); // '53' (number -> string)
console.log(5 + '3'); // '53' (number -> string)
console.log('5' + true); // '5true'
// + with numbers = addition
console.log(5 + 3); // 8
console.log(true + true); // 2 (boolean -> number)
console.log(null + 1); // 1 (null -> 0)
// Other operators always convert to number
console.log('6' - 1); // 5 (string -> number)
console.log('6' * '2'); // 12
console.log('abc' - 1); // NaN
// Explicit conversion
console.log(Number('')); // 0
console.log(Number('abc')); // NaN
console.log(Number(true)); // 1
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
The + operator prefers string concatenation if either operand is a string. Other math operators (-, *, /) always convert to numbers.
Type Coercion, == vs ===, Truthy/Falsy, String Conversion, Number Conversion