Arunkumar

JavaScript Data Types: A Complete Interview Guide

14 min read2,633 wordsJavaScript

Why Understanding Data Types Matters

JavaScript's type system is fundamental to the language, yet it's full of quirks that trip up even experienced developers. Understanding data types is crucial for:

  • Writing predictable code - Knowing how values behave in memory
  • Debugging effectively - Understanding why comparisons fail
  • Acing technical interviews - Data types are a favorite interview topic
  • Avoiding common bugs - Type coercion and reference issues

This guide covers everything you need to know about JavaScript data types, from the basics to advanced interview questions.


The Two Categories: Primitive vs Reference Types

JavaScript divides data types into two fundamental categories:

Primitive Types (Value Types)

  • Stored directly in the variable
  • Immutable (cannot be changed, only replaced)
  • Compared by value
  • Stored on the stack

Reference Types (Non-Primitive Types)

  • Stored as references to memory locations
  • Mutable (can be modified)
  • Compared by reference
  • Stored on the heap

Primitive Data Types

JavaScript has 7 primitive data types (ES2020+). Here's a complete breakdown:

TypeDescriptionExampletypeof Result
numberNumeric values (integers and floats)42, 3.14, NaN, Infinity"number"
stringSequence of characters"hello", 'world', `template`"string"
booleanLogical true/falsetrue, false"boolean"
undefinedVariable declared but not assignedundefined"undefined"
nullIntentional absence of valuenull"object" ⚠️
symbolUnique, immutable identifierSymbol('id')"symbol"
bigintArbitrary precision integers9007199254740991n"bigint"

1. Number

JavaScript uses a single number type for both integers and floating-point numbers.

let integer = 42;
let float = 3.14159;
let negative = -10;
let scientific = 1e5; // 100000
let hex = 0xff; // 255
let binary = 0b1010; // 10
let octal = 0o755; // 493

console.log(typeof integer); // "number"
console.log(typeof float); // "number"

Special Number Values:

let notANumber = NaN; // Not a Number
let infinity = Infinity; // Positive infinity
let negativeInfinity = -Infinity; // Negative infinity

console.log(NaN === NaN); // false ⚠️
console.log(isNaN(NaN)); // true
console.log(Number.isNaN(NaN)); // true (preferred)

Interview Trap: NaN !== NaN is always true. Use Number.isNaN() or isNaN() to check.

2. String

Strings are sequences of characters, immutable once created.

let single = "Single quotes";
let double = "Double quotes";
let template = `Template literals ${single}`; // ES6+

console.log(typeof single); // "string"

// String methods return new strings (immutability)
let str = "hello";
str.toUpperCase(); // Returns "HELLO", doesn't modify str
console.log(str); // "hello" (unchanged)

3. Boolean

Only two values: true and false.

let isActive = true;
let isComplete = false;

console.log(typeof isActive); // "boolean"

// Truthy and falsy values
if (0) {
} // falsy
if (1) {
} // truthy
if ("") {
} // falsy
if ("hello") {
} // truthy
if (null) {
} // falsy
if (undefined) {
} // falsy

4. Undefined

A variable that has been declared but not assigned a value.

let x;
console.log(x); // undefined
console.log(typeof x); // "undefined"

// Undefined vs not declared
let y;
console.log(y); // undefined
// console.log(z); // ReferenceError: z is not defined

5. Null

Represents the intentional absence of any value. This is a famous JavaScript quirk:

let empty = null;
console.log(typeof empty); // "object" ⚠️ (BUG in JavaScript!)
console.log(null === null); // true
console.log(null == undefined); // true (loose equality)
console.log(null === undefined); // false (strict equality)

Interview Trap: typeof null returns "object" - this is a known bug in JavaScript that can't be fixed due to backward compatibility.

6. Symbol

Introduced in ES6, symbols are unique and immutable identifiers.

let id1 = Symbol("id");
let id2 = Symbol("id");
console.log(id1 === id2); // false (always unique)

// Global symbol registry
let globalId = Symbol.for("id");
let sameGlobalId = Symbol.for("id");
console.log(globalId === sameGlobalId); // true

console.log(typeof id1); // "symbol"

7. BigInt

Introduced in ES2020, for integers larger than Number.MAX_SAFE_INTEGER.

let bigNumber = 9007199254740991n; // Note the 'n' suffix
let anotherBig = BigInt(9007199254740991);

console.log(typeof bigNumber); // "bigint"

// Cannot mix with regular numbers
// let sum = bigNumber + 1; // TypeError
let sum = bigNumber + 1n; // OK

Reference Data Types (Objects)

Everything that's not a primitive is an object (or behaves like one).

Objects

let person = {
  name: "John",
  age: 30,
};

console.log(typeof person); // "object"

Arrays

Arrays are objects with numeric indices.

let fruits = ["apple", "banana", "orange"];
console.log(typeof fruits); // "object" ⚠️

// Check if array
console.log(Array.isArray(fruits)); // true (preferred)
console.log(fruits instanceof Array); // true

Interview Trap: typeof [] returns "object", not "array". Use Array.isArray().

Functions

Functions are first-class objects in JavaScript.

function greet() {
  return "Hello";
}

console.log(typeof greet); // "function"

Dates, RegExp, and More

let date = new Date();
let regex = /pattern/;
let error = new Error("message");

console.log(typeof date); // "object"
console.log(typeof regex); // "object"
console.log(typeof error); // "object"

Memory Behavior: Stack vs Heap

Understanding where data is stored is crucial for understanding JavaScript's behavior.

Stack (Primitive Types)

The stack is fast, limited memory where primitive values are stored directly.

let a = 10;
let b = a; // Copy of value
b = 20;
console.log(a); // 10 (unchanged)
console.log(b); // 20

What happens:

  1. a is stored on the stack with value 10
  2. b = a creates a copy of the value
  3. Changing b doesn't affect a

Heap (Reference Types)

The heap is larger, slower memory where objects are stored. Variables hold references (pointers) to heap locations.

let obj1 = { value: 10 };
let obj2 = obj1; // Copy of reference, not value!
obj2.value = 20;
console.log(obj1.value); // 20 ⚠️ (changed!)
console.log(obj2.value); // 20

What happens:

  1. obj1 is stored on the stack, pointing to an object on the heap
  2. obj2 = obj1 copies the reference, not the object
  3. Both variables point to the same object on the heap
  4. Modifying through either variable affects the same object

Visual Representation:

// Stack          Heap
// a: 10
// b: 20

// Stack          Heap
// obj1: [ref] ──→ { value: 20 }
// obj2: [ref] ──┘

Pass-by-Value vs Pass-by-Reference

JavaScript is always pass-by-value, but the "value" for objects is a reference.

Primitive Types: Pass-by-Value

function changeValue(x) {
  x = 20; // Changes local copy
}

let num = 10;
changeValue(num);
console.log(num); // 10 (unchanged)

Reference Types: Pass-by-Value (of Reference)

function changeObject(obj) {
  //obj receives a copy of the reference, Both(obj and myObj) point to the same object

  obj.value = 20; // Modifies the object
  obj = { value: 30 }; // Reassigns local reference
}

let myObj = { value: 10 };
changeObject(myObj);
console.log(myObj.value); // 20 (modified, not 30!)

Why obj.value changed but obj didn't:

  • obj.value = 20 modifies the shared object
  • obj = { value: 30 } only reassigns the local reference
  • The original myObj still points to the original object

More Examples

// Primitive: Value copied
let a = 5;
let b = a;
b = 10;
console.log(a, b); // 5, 10

// Object: Reference copied
let arr1 = [1, 2, 3];
let arr2 = arr1;
arr2.push(4);
console.log(arr1, arr2); // [1,2,3,4], [1,2,3,4] (same array!)

// Creating a copy
let arr3 = [...arr1]; // Shallow copy
arr3.push(5);
console.log(arr1, arr3); // [1,2,3,4], [1,2,3,4,5] (different arrays)

Common Interview Trap Questions

Trap 1: typeof null

console.log(typeof null); // "object" ⚠️

// Correct way to check for null
let value = null;
if (value === null) {
  console.log("It's null");
}

// Or use nullish coalescing
let result = value ?? "default";

Why: This is a bug in JavaScript from the first implementation. It can't be fixed without breaking existing code.

Trap 2: Object Comparison

let obj1 = { name: "John" };
let obj2 = { name: "John" };
let obj3 = obj1;

console.log(obj1 === obj2); // false ⚠️ (different references)
console.log(obj1 === obj3); // true (same reference)

// Deep comparison needed
function deepEqual(a, b) {
  return JSON.stringify(a) === JSON.stringify(b);
}
console.log(deepEqual(obj1, obj2)); // true (but has limitations)

Why: Objects are compared by reference, not by value.

Trap 3: Array Type Checking

let arr = [1, 2, 3];
console.log(typeof arr); // "object" ⚠️

// Wrong way
if (typeof arr === "array") {
} // Never true!

// Correct ways
if (Array.isArray(arr)) {
} // ✅ Preferred
if (arr instanceof Array) {
} // ✅ Also works

Trap 4: NaN Comparison

let result = NaN;
console.log(result === NaN); // false ⚠️
console.log(result == NaN); // false ⚠️

// Correct ways
console.log(Number.isNaN(result)); // true ✅ (preferred)
console.log(isNaN(result)); // true (but has quirks)

Why: NaN is the only value that is not equal to itself.

Trap 5: Type Coercion

console.log([] == false); // true ⚠️
console.log([] === false); // false
console.log("5" == 5); // true ⚠️
console.log("5" === 5); // false

// Always use === for strict equality

Trap 6: Mutable Primitives (Wrapper Objects)

let str = "hello";
str.property = "value";
console.log(str.property); // undefined ⚠️

// Why: Primitives are immutable
// When you access a property, JS creates a temporary wrapper object

Real Interview Questions with Answers

Q1: What's the difference between primitive and reference types?

Answer:

  • Primitive types are stored directly in variables, immutable, compared by value, and stored on the stack. Examples: number, string, boolean, null, undefined, symbol, bigint.
  • Reference types are stored as references to memory locations, mutable, compared by reference, and stored on the heap. Examples: object, array, function, Date, RegExp.

Q2: What will this code output?

let a = { x: 1 };
let b = a;
b.x = 2;
console.log(a.x);

Answer: 2

Explanation: b holds a reference to the same object as a. Modifying b.x changes the shared object, so a.x is also 2.

Q3: What's the output of typeof null and why?

Answer: "object"

Explanation: This is a known bug in JavaScript from the first implementation. The typeof operator incorrectly returns "object" for null. To check for null, use strict equality: value === null.

Q4: How do you check if a variable is an array?

Answer:

Array.isArray(variable); // ✅ Preferred
variable instanceof Array; // ✅ Also works
typeof variable === "array"; // ❌ Never works (typeof returns "object")

Q5: What's the difference between == and ===?

Answer:

  • == (loose equality) performs type coercion before comparison
  • === (strict equality) compares both value and type without coercion

Examples:

"5" == 5; // true (coercion)
"5" === 5; // false (different types)
null == undefined; // true
null === undefined; // false

Q6: What will this code output?

let x = NaN;
console.log(x === NaN);
console.log(Number.isNaN(x));

Answer:

false;
true;

Explanation: NaN is the only value that is not equal to itself. Use Number.isNaN() or isNaN() to check for NaN.

Q7: Explain pass-by-value vs pass-by-reference in JavaScript.

Answer: JavaScript is always pass-by-value. For primitives, the value itself is passed. For objects, the value passed is a reference (pointer) to the object. This means:

  • Primitive parameters are independent copies
  • Object parameters share the same reference, so mutations are visible to the caller

Q8: What's the output?

function test(obj) {
  obj = { value: 20 };
}

let myObj = { value: 10 };
test(myObj);
console.log(myObj.value);

Answer: 10

Explanation: Reassigning obj inside the function only changes the local reference. The original myObj still points to { value: 10 }.

Q9: How many primitive types are in JavaScript?

Answer: 7 primitive types:

  1. number
  2. string
  3. boolean
  4. undefined
  5. null
  6. symbol
  7. bigint

Q10: What's the difference between undefined and null?

Answer:

  • undefined: Variable declared but not assigned, or property doesn't exist
  • null: Intentional absence of value (explicitly set)
let x; // undefined
let y = null; // null (intentional)

console.log(x == null); // true (loose equality)
console.log(x === null); // false (strict equality)

Type Checking Best Practices

Use Strict Equality (===)

// ❌ Avoid
if (value == 5) {
}

// ✅ Prefer
if (value === 5) {
}

Check for null/undefined

// ✅ Explicit checks
if (value === null) {
}
if (value === undefined) {
}
if (value == null) {
} // Checks both null and undefined

// ✅ Modern approach
if (value == null) {
} // nullish check
let result = value ?? "default"; // nullish coalescing

Array Checking

// ✅ Always use
if (Array.isArray(value)) {
}

// ❌ Never use
if (typeof value === "array") {
} // Never true!

NaN Checking

// ✅ Preferred
if (Number.isNaN(value)) {
}

// ⚠️ Works but has quirks
if (isNaN(value)) {
} // Coerces value first

Type Guards

function isString(value) {
  return typeof value === "string";
}

function isNumber(value) {
  return typeof value === "number" && !isNaN(value);
}

function isObject(value) {
  return value !== null && typeof value === "object";
}

Key Takeaways

  1. JavaScript has 7 primitive types and everything else is an object
  2. Primitives are immutable - operations return new values
  3. Objects are mutable - modifications affect all references
  4. Memory model matters - stack for primitives, heap for objects
  5. Always use === for comparisons to avoid type coercion
  6. typeof null is "object" - it's a bug, use === null to check
  7. typeof [] is "object" - use Array.isArray() to check arrays
  8. NaN !== NaN - use Number.isNaN() to check
  9. JavaScript is pass-by-value - but object values are references
  10. Understand reference vs value - critical for avoiding bugs

Interview Tips

Before the Interview

  1. Memorize the 7 primitive types - This is often asked directly
  2. Practice object comparison - Know why {} === {} is false
  3. Understand typeof quirks - null and arrays return "object"
  4. Know memory behavior - Stack vs heap, pass-by-value
  5. Practice code tracing - Be able to predict outputs

During the Interview

  1. Think out loud - Explain your reasoning
  2. Ask clarifying questions - "Should I use strict or loose equality?"
  3. Mention edge cases - Show you know the traps
  4. Use correct terminology - "reference type" not "object type"
  5. Draw diagrams - Visualize stack/heap when explaining

Common Follow-ups

  • "How would you implement deep equality?"
  • "What's the difference between Object.is() and ===?"
  • "How does garbage collection work with references?"
  • "Explain the difference between shallow and deep copying"

Summary

JavaScript's type system is deceptively simple but full of nuances:

  • 7 primitive types stored on the stack, compared by value
  • Reference types stored on the heap, compared by reference
  • Memory behavior determines how values are copied and compared
  • Type coercion can cause unexpected behavior - always use strict equality
  • Common traps like typeof null and array checking trip up many developers

Mastering these concepts is essential for writing robust JavaScript and acing technical interviews. Remember: understanding why something behaves a certain way is more valuable than memorizing facts.

Pro tip: When in doubt, use strict equality (===), Array.isArray(), and explicit type checks. It's better to be explicit than to rely on JavaScript's quirky type coercion.

Related Articles