Topics in this subject
JavaScript 3 min read Updated 4 Aug 2026

Part 5 — Data Types

Primitives, Reference types, typeof, instanceof, Object.prototype.toString, Boxing and wrapper objects

JavaScript has 8 types: 7 primitives + object.

graph TD
    T[JavaScript Types] --> P[Primitives<br/>immutable, copied by value]
    T --> O[Object<br/>mutable, copied by reference]
    P --> S1[string]
    P --> S2[number]
    P --> S3[bigint]
    P --> S4[boolean]
    P --> S5[undefined]
    P --> S6[null]
    P --> S7[symbol]
    O --> O1[plain object]
    O --> O2[Array]
    O --> O3[Function]
    O --> O4[Date, Map, Set, RegExp, ...]

Primitives#

Type Example Notes
string "hi", 'hi', `hi` UTF-16 sequences; immutable
number 42, 3.14, Infinity, NaN IEEE-754 double (Part 13)
bigint 9007199254740993n Arbitrary-precision integers
boolean true, false
undefined undefined "declared but no value"
null null "intentional absence"
symbol Symbol("id") Unique, used as hidden keys

Primitives are immutable. "abc".toUpperCase() returns a new string; it doesn't change the original.

⚠️ null vs undefined:

  • undefined — the engine's "not set yet" (uninitialized vars, missing params, missing props).
  • nullyour "deliberately empty."
  • typeof undefined === "undefined", but typeof null === "object" — a 25-year-old bug kept for compatibility. 🎯

Reference types#

Objects, arrays, functions, Date, Map, Set, WeakMap, WeakSet, RegExp, etc. All are objects underneath, all copied by reference.

  • Map — key→value store where any value can be a key (objects too), preserves insertion order, has .size. Prefer over plain objects for dynamic dictionaries.
  • Set — unique values. Great for dedupe: [...new Set(arr)].
  • WeakMap / WeakSet — keys must be objects and are weakly held: if nothing else references the key, it can be garbage-collected (and its entry vanishes). Not iterable, no .size. Use for private data / caches keyed by object without causing leaks.
const cache = new WeakMap();
function compute(objKey) {
  if (cache.has(objKey)) return cache.get(objKey);
  const result = /* expensive */ objKey.id * 2;
  cache.set(objKey, result);   // entry disappears when objKey is GC'd
  return result;
}

typeof, instanceof, Object.prototype.toString#

typeof "hi"        // "string"
typeof 42          // "number"
typeof 10n         // "bigint"
typeof true        // "boolean"
typeof undefined   // "undefined"
typeof null        // "object"   ⚠️ the famous bug
typeof Symbol()    // "symbol"
typeof function(){}// "function" ⚠️ functions get their own answer
typeof []          // "object"   (arrays are objects)
typeof {}          // "object"

typeof is unreliable for distinguishing object kinds. Use:

Array.isArray([])                       // true — the correct array check
[] instanceof Array                     // true, but fails across iframes/realms
Object.prototype.toString.call([])      // "[object Array]"
Object.prototype.toString.call(null)    // "[object Null]"
Object.prototype.toString.call(/x/)     // "[object RegExp]"

instanceof checks whether a constructor's .prototype appears in an object's prototype chain — so it can be fooled and breaks across realms. Object.prototype.toString.call(x) is the most robust type tag. 🎯

Boxing and wrapper objects#

ELI12. "hi" is a primitive with no methods, yet "hi".toUpperCase() works. Behind the scenes JavaScript temporarily wraps the primitive in a String object, calls the method, then throws the wrapper away. This is autoboxing.

const s = "hi";
s.custom = 1;        // silently wraps, sets prop on a throwaway object
console.log(s.custom); // undefined — the wrapper was discarded

typeof new String("hi")  // "object" ⚠️ — never use `new String/Number/Boolean`
new Boolean(false) ? "truthy!" : "falsy"  // "truthy!" — objects are always truthy 🎯

🔴 Never use wrapper constructors (new String, new Number, new Boolean). Call them without new for conversion (Number("42")) instead.

Interview questions (Part 5):

  1. Why is typeof null === "object"? Name two robust alternatives for type checking.
  2. Difference between null and undefined, and what each idiomatically signals.
  3. When would you choose Map over a plain object? WeakMap over Map?
  4. Explain autoboxing. Why is new Boolean(false) truthy?