Online Compiler logoOnline Compiler

JavaScript Tutorial

JavaScript Data Types: Primitives and Objects

Data types define how values behave in memory and operations. Strong type awareness prevents runtime errors and logical bugs.

Why this matters

Type confusion causes common issues like incorrect comparisons, unexpected coercion, and method errors.

Primitive Data Types

JavaScript has seven primitive data types. Primitives are immutable values that are stored directly in memory.

string: Textual data, enclosed in quotes, immutable sequence of characters.
number: Numeric values including integers and floating-point numbers.
bigint: Arbitrary-precision integers for large numbers beyond Number.MAX_SAFE_INTEGER.
boolean: Logical values true or false.
undefined: Value assigned to variables that have been declared but not initialized.
null: Intentional absence of any object value.
symbol: Unique and immutable primitive values, often used as object property keys.

Primitives are compared by value, not reference. Operations on primitives create new values.

Primitive Type Examples

// String
const name = "Alice";
console.log(typeof name); // "string"

// Number
const age = 25;
const price = 19.99;
console.log(typeof age); // "number"

// BigInt
...

Each primitive type has distinct characteristics and use cases.

Reference Data Types

Objects, arrays, and functions are reference types. They store references to memory locations containing the actual data.

Object: Collection of key-value pairs, most flexible data structure.
Array: Ordered collection of values, indexed by numbers.
Function: Callable objects that execute code when invoked.

Reference types are compared by reference, not value. Assignment copies the reference, not the data.

Reference Type Behavior

// Object
const person = { name: "Alice", age: 25 };
console.log(typeof person); // "object"

// Array
const numbers = [1, 2, 3, 4, 5];
console.log(typeof numbers); // "object" (arrays are objects)

// Function
function greet() {
...

Reference types store references to data, not the data itself.

Type Checking and Conversion

Understanding type checking and implicit/explicit conversion is crucial for writing robust JavaScript code.

typeof operator: Returns string indicating the type of operand.
instanceof operator: Tests if object is instance of constructor.
Explicit conversion: Using Number(), String(), Boolean() constructors.
Implicit coercion: Automatic type conversion in operations (often problematic).

Prefer explicit conversion and strict equality to avoid unexpected behavior.

Type Checking

// typeof operator
console.log(typeof "hello");     // "string"
console.log(typeof 42);          // "number"
console.log(typeof true);        // "boolean"
console.log(typeof undefined);   // "undefined"
console.log(typeof null);        // "object" (quirk)
console.log(typeof []);          // "object"
console.log(typeof {});          // "object"
console.log(typeof function(){}); // "function"

...

Use typeof for primitives, instanceof for objects.

Type Conversion

// Explicit conversion
console.log(Number("42"));       // 42
console.log(String(123));        // "123"
console.log(Boolean(0));         // false
console.log(Boolean(1));         // true

// Implicit coercion (avoid when possible)
console.log("5" + 3);            // "53" (string concatenation)
console.log("5" - 3);            // 2 (numeric subtraction)
console.log(5 + true);           // 6 (boolean to number)
...

Explicit conversion is predictable, implicit coercion can cause bugs.

Copying and Mutation

Understanding how data is copied and mutated is essential for avoiding unintended side effects.

Primitive copying: Always creates independent copies (pass by value).
Reference copying: Copies the reference, not the data (pass by reference).
Shallow copy: Creates new object but nested references remain shared.
Deep copy: Creates completely independent copy of all nested data.

Use appropriate copying strategies based on data structure and mutation needs.

Shallow vs Deep Copy

// Primitive copy (independent)
let a = 10;
let b = a;
b = 20;
console.log(a, b); // 10, 20

// Reference copy (shared)
const obj1 = { name: "Alice" };
const obj2 = obj1;
obj2.name = "Bob";
...

Primitives copy by value, objects copy by reference.

Best Practices

Use strict equality (===) to avoid unexpected type coercion in comparisons.

Check for null and undefined explicitly rather than relying on truthiness.

Use typeof for primitive type checks and instanceof for object type checks.

Prefer explicit type conversion over implicit coercion for predictable behavior.

Use structuredClone for deep copying when available, or implement proper deep copy strategies.

Be aware of the typeof null quirk and handle null checks appropriately.

Common Mistakes and Fixes

Using == instead of ===

Loose equality performs type coercion that can lead to unexpected results.

Fix: Always use strict equality (===)

Treating null and undefined as equivalent

They represent different concepts and should be handled intentionally.

Fix: Check for both explicitly when needed

Assuming object assignment clones data

Object assignment copies references, not values, leading to shared mutations.

Fix: Use copy patterns like spread or structuredClone