Types, Values, Equality, and Coercion
Go beyond primitive type lists and understand JavaScript's value model, coercion rules, equality algorithms, and the surprising cases that appear in real applications.
Primitive Values
JavaScript has seven primitive data types: string, number, bigint, boolean, undefined, symbol, and null. Primitives are immutable values. Objects, functions, arrays, dates, maps, sets, and other compound structures are objects.
number uses IEEE 754 double-precision floating-point representation, which means integers and fractional values share the same type. bigint exists for integers outside the safe integer range of number.
console.log(typeof 'hello');
console.log(typeof 42);
console.log(typeof 42n);
console.log(typeof true);
console.log(typeof undefined);
console.log(typeof Symbol('id'));
console.log(typeof null);typeof null, which returns "object" for historical compatibility.- Primitive values are immutable.
- BigInt is intended for arbitrary-size integers.
typeof nullreturning object is a historical language quirk.
How many primitive data types does modern JavaScript define?
Numbers, NaN, Infinity, and Precision
JavaScript's number type is a 64-bit IEEE 754 floating-point value. This means many decimal fractions cannot be represented exactly in binary. Therefore 0.1 + 0.2 is not exactly 0.3.
The largest integer that can be represented safely as an integer by number is Number.MAX_SAFE_INTEGER. For exact arithmetic involving larger integers, use BigInt. NaN means the result is not a valid numeric value and has the unusual property that it is not equal to itself.
console.log(0.1 + 0.2);
console.log(Number.isNaN(NaN));
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER));
console.log(9007199254740993n);- Do not assume decimal arithmetic is exact.
- Use Number.isNaN rather than global isNaN when validating actual NaN values.
- Use BigInt for integer calculations that exceed Number's safe range.
Why does `0.1 + 0.2 === 0.3` evaluate to false?
Truthy and Falsy Values
JavaScript converts values to boolean in contexts such as if, logical operators, and conditional expressions. Falsy values include false, 0, -0, 0n, "", null, undefined, and NaN. Everything else is truthy, including empty arrays and empty objects.
This distinction is important because developers often incorrectly assume that an empty array or object is falsy.
if ([]) {
console.log('empty array is truthy');
}
if ({}) {
console.log('empty object is truthy');
}- Empty arrays and objects are truthy.
- Falsy is a specific set of values, not a general concept of emptiness.
- Use explicit checks when zero, empty strings, or null-like values have different meanings.
Which value is falsy?
Strict Equality vs Loose Equality
=== uses strict equality and does not perform the ordinary type coercion associated with ==. For most application code, strict equality makes intent easier to understand. Loose equality has a defined coercion algorithm and is not random, but its behavior is sufficiently complex that it should be used deliberately.
Remember that NaN !== NaN, while Object.is(NaN, NaN) is true. Object.is also distinguishes 0 and -0.
console.log(1 === '1');
console.log(1 == '1');
console.log(NaN === NaN);
console.log(Object.is(NaN, NaN));
console.log(Object.is(0, -0));- Prefer
===for ordinary equality checks. ==performs a defined but sometimes surprising coercion process.Object.isdiffers from===for NaN and signed zero.
Which expression evaluates to true?
Nullish Coalescing and Optional Chaining
The nullish coalescing operator ?? chooses the right-hand value only when the left-hand side is null or undefined. This differs from ||, which treats every falsy value as a reason to use the fallback.
Optional chaining ?. allows property, method, and element access to stop safely when the preceding value is nullish.
const pageSize = 0;
console.log(pageSize || 20);
console.log(pageSize ?? 20);
const user = {};
console.log(user.profile?.address?.city ?? 'Unknown');|| expression treats zero as falsy and returns 20. The ?? expression preserves zero because zero is not nullish.- Use
??when only null and undefined should trigger a fallback. - Use
||when any falsy value should trigger a fallback. - Optional chaining prevents errors while traversing nullish values.
What does `0 ?? 10` return?