What are the different data types in JavaScript?

Beginner8 min interview
Skills tested:
Primitive vs reference type distinctiontypeof operator behavior and its known quirksValue vs reference equalityImmutability of primitivesDynamic typing and implicit coercion awareness

Advertisement

🧩 Scenario

In a real codebase, you will encounter data type behavior in equality checks, API response handling, state comparisons, and function argument validation. A mismatch between expected and actual types is behind a large percentage of runtime bugs in JavaScript, especially in dynamically typed codebases where type information is not enforced at compile time. Understanding how each type is stored and compared gives you the foundation to reason about bugs involving coercion, mutation, and unexpected equality results.

Architecture Walkthrough

The Seven Primitive Types

JavaScript has seven primitive types: string, number, boolean, undefined, null, symbol, and bigint. Primitive values are immutable, meaning the value itself cannot be changed. When you reassign a variable that holds a primitive, you are replacing the reference to the old value with a reference to a new one, not modifying the original.

Primitives are compared by value. Two variables holding the same string or number are considered equal when compared with ===. undefined represents a variable that has been declared but not yet assigned a value. null is an intentional assignment that represents the absence of a value. Symbol creates a guaranteed-unique identifier useful for property keys that must not collide. BigInt handles integers larger than Number.MAX_SAFE_INTEGER (2^53 - 1).

The Object Type and Reference Behavior

Everything that is not a primitive is an object in JavaScript. This includes plain objects, arrays, functions, dates, maps, and sets. Objects are stored as references: a variable holds a pointer to the memory location where the data lives, not the data itself.

Reference comparison means two distinct object literals with identical content are not equal when compared with ===. They are separate allocations in memory. Only when two variables point to the exact same object in memory will a strict equality check return true. This distinction is critical for understanding state comparison in React, caching, and deep equality checks.

typeof and Its Known Quirks

The typeof operator returns a string describing the type of a value. For most primitives it behaves as expected. However, typeof null returns "object", which is a longstanding bug in the language that was not fixed to preserve backward compatibility. typeof for a function returns "function" even though functions are objects. And typeof for an array also returns "object", so you need Array.isArray() to reliably check for arrays.

Knowing these quirks matters because typeof is still the most common way to check types in JavaScript, and misreading its output leads to incorrect conditional branches and silent bugs.


Key Code Explained

// Primitive: comparison by value
const a = 'hello';
const b = 'hello';
console.log(a === b); // true

// Object: comparison by reference
const obj1 = { name: 'Ghazi' };
const obj2 = { name: 'Ghazi' };
console.log(obj1 === obj2); // false — different objects in memory
const obj3 = obj1;
console.log(obj1 === obj3); // true — same reference

// typeof quirks
console.log(typeof null); // "object" (historical bug)
console.log(typeof []); // "object" (not "array")
console.log(typeof function () {}); // "function"
console.log(Array.isArray([])); // true — correct way to check for arrays

// Primitives passed to functions do not mutate the original
function increment(n) {
  n++;
  return n;
}
let count = 5;
increment(count);
console.log(count); // still 5

// Objects passed to functions share the reference
function rename(user) {
  user.name = 'Ali';
}
const person = { name: 'Ghazi' };
rename(person);
console.log(person.name); // 'Ali' — the original was mutated

The function examples demonstrate a key consequence of the primitive/reference distinction. Primitives are effectively passed by value, so changes inside a function do not affect the caller. Objects are passed by reference (technically "pass by sharing"), so mutations inside a function affect the original object.


Tradeoffs

AspectPrimitivesObjects (Reference Types)
StorageBy value, independent copyBy reference, shared pointer
Equality=== compares actual values=== compares memory addresses
MutabilityImmutable, reassignment onlyMutable, properties can change in place

What Interviewers Actually Check

  • Whether you can list all 7 primitive types without confusing the list
  • Whether you know typeof null === "object" and why it returns that
  • Whether you understand that arrays and functions are objects in JavaScript
  • Whether you can correctly predict equality behavior for both primitives and objects
  • Whether you know what undefined and null each represent and when each is appropriate
  • Whether you can explain pass-by-value vs pass-by-reference using a function argument example

Follow-Up Questions

  1. How does JavaScript's dynamic typing differ from TypeScript's type system, and what category of bugs does TypeScript prevent?
  2. If you need to check whether a variable is an array, what is the most reliable way and why not typeof?
  3. How would you write a utility function to perform deep equality comparison between two objects?
  4. Why does NaN !== NaN evaluate to true, and how do you correctly check for NaN?
  5. In a high-volume data processing pipeline, would you prefer strings or numbers as map keys for performance, and why?

Common Candidate Mistakes

  • Expecting typeof null to return "null" when it returns "object", which is a known language bug
  • Assuming two objects with identical contents are equal when compared with ===
  • Confusing undefined (declared but not assigned) with null (intentionally empty), or using them interchangeably
  • Forgetting that arrays and functions are objects under the hood, causing incorrect typeof assumptions
  • Not knowing that Symbol() produces a unique value every time it is called, even with the same description string

Interview Readiness Checklist

Before you leave this question, make sure you can answer:

  • Can you list all 7 primitive types from memory?
  • Can you explain what typeof null returns and why that is considered a historical bug?
  • Can you demonstrate value equality for primitives and reference equality for objects with a code example?
  • Can you explain what happens when you reassign a primitive variable versus when you mutate an object property?
  • Can you name a real use case for Symbol and BigInt?
  • Can you explain what dynamic typing means and give an example of a type coercion pitfall?

Summary

JavaScript has seven primitive types: string, number, boolean, undefined, null, symbol, and bigint. These are immutable and compared by value. Everything else is an object, a reference type that is mutable and compared by memory address rather than content.

The practical consequences of this split appear constantly: equality checks between two objects with the same contents return false, functions that mutate object arguments affect the caller, and cloning requires explicit effort. The typeof operator is the primary tool for runtime type checking, but it has well-known quirks around null, arrays, and functions that every JavaScript developer must know.

Understanding this foundation makes the rest of JavaScript's behavior predictable. Type coercion, loose equality, state comparison in React, and the entire cloning topic all depend on knowing which types are primitives and which are references.

Related Videos
Watch these videos to learn more about this topic
Frequently Asked Questions

Is JavaScript strongly typed?

No, JavaScript is dynamically typed — variables can change type at runtime.

Advertisement


Stay Updated

Get the latest frontend challenges, interview questions and tutorials delivered to your inbox.

Advertisement