Skip to content

JavaScript Reference Data Types: Objects, Arrays, and Functions

If basic data types are individual LEGO bricks, then reference data types are complex models built from these bricks. They can contain multiple values, can be nested and combined, and can express more complex data structures and business logic.

Reference Types vs Basic Types

Before delving deep into reference types, we need to understand their fundamental differences from basic types.

Storage Method Differences

javascript
// Basic types: store values directly
let num1 = 42;
let num2 = num1; // Copy value

num2 = 100; // Modifying num2 doesn't affect num1
console.log(num1); // 42
console.log(num2); // 100

// Reference types: store references (addresses)
let obj1 = { name: "Alice" };
let obj2 = obj1; // Copy reference, not copy object

obj2.name = "Bob"; // Modify through obj2, obj1 also changes!
console.log(obj1.name); // "Bob"
console.log(obj2.name); // "Bob"

This is like buying a house: basic types are directly owning a copy of the house, while reference types hold the address of the house. Changing the house pointed to by the address, everyone holding this address will see the changes.

Comparison Method Differences

javascript
// Basic types: compare values
console.log(5 === 5); // true
console.log("hello" === "hello"); // true

// Reference types: compare references (addresses)
console.log({} === {}); // false (different objects, different addresses)
console.log([] === []); // false (different arrays, different addresses)

let arr1 = [1, 2, 3];
let arr2 = arr1; // Same reference
console.log(arr1 === arr2); // true (point to same array)

// Even with identical content, if they're different objects, they're not equal
let person1 = { name: "Charlie", age: 30 };
let person2 = { name: "Charlie", age: 30 };
console.log(person1 === person2); // false (different objects)

Object Type

Objects are the most important data type in JavaScript, like a storage cabinet full of labeled boxes, where each box (property) has a label (key) and content (value).

Creating Objects

javascript
// Method 1: Object literal (most common)
let user = {
  name: "David",
  age: 28,
  email: "[email protected]",
};

// Method 2: new Object()
let person = new Object();
person.name = "Emma";
person.age = 32;

// Method 3: Object.create()
let student = Object.create(null);
student.grade = "A";

// Method 4: Constructor function
function Person(name, age) {
  this.name = name;
  this.age = age;
}
let john = new Person("John", 25);

Accessing and Modifying Properties

javascript
let user = {
  name: "Sarah",
  age: 27,
  email: "[email protected]",
};

// Dot notation access
console.log(user.name); // "Sarah"
console.log(user.age); // 27

// Bracket notation access
console.log(user["email"]); // "[email protected]"

// Modify properties
user.age = 28;
user["email"] = "[email protected]";

// Add new properties
user.city = "London";
user["country"] = "UK";

console.log(user);
// {
//   name: "Sarah",
//   age: 28,
//   email: "[email protected]",
//   city: "London",
//   country: "UK"
// }

// Delete properties
delete user.country;
console.log(user.country); // undefined

Applications of Bracket Notation

Bracket notation is more flexible and can use variables and special characters:

javascript
// Use variables as property names
let propertyName = "age";
console.log(user[propertyName]); // 28

// Property names containing spaces or special characters
let config = {
  "api-key": "abc123",
  "user name": "Tom",
  "is-active": true,
};

console.log(config["api-key"]); // "abc123"
console.log(config["user name"]); // "Tom"

// config.api-key  // This would cause an error!

// Dynamic property names
let key = "score";
let value = 95;

let exam = {
  [key]: value, // ES6 computed property name
};
console.log(exam.score); // 95

Object Methods

Objects can contain functions as properties, these functions are called methods:

javascript
let calculator = {
  value: 0,

  add: function (num) {
    this.value += num;
    return this;
  },

  subtract: function (num) {
    this.value -= num;
    return this;
  },

  // ES6 simplified syntax
  multiply(num) {
    this.value *= num;
    return this;
  },

  getValue() {
    return this.value;
  },
};

calculator.add(10).multiply(2).subtract(5);
console.log(calculator.getValue()); // 15

Checking if Properties Exist

javascript
let user = {
  name: "Oliver",
  age: 35,
};

// Method 1: in operator
console.log("name" in user); // true
console.log("email" in user); // false

// Method 2: hasOwnProperty method
console.log(user.hasOwnProperty("age")); // true
console.log(user.hasOwnProperty("email")); // false

// Method 3: Direct access and check (note: returns false when value is undefined)
console.log(user.name !== undefined); // true
console.log(user.email !== undefined); // false

Traversing Objects

javascript
let product = {
  name: "Laptop",
  price: 1200,
  brand: "TechCorp",
  inStock: true,
};

// for...in loop
for (let key in product) {
  console.log(key + ": " + product[key]);
}
// name: Laptop
// price: 1200
// brand: TechCorp
// inStock: true

// Object.keys()
let keys = Object.keys(product);
console.log(keys); // ["name", "price", "brand", "inStock"]

// Object.values()
let values = Object.values(product);
console.log(values); // ["Laptop", 1200, "TechCorp", true]

// Object.entries()
let entries = Object.entries(product);
console.log(entries);
// [
//   ["name", "Laptop"],
//   ["price", 1200],
//   ["brand", "TechCorp"],
//   ["inStock", true]
// ]

entries.forEach(([key, value]) => {
  console.log(`${key}: ${value}`);
});

Array Type

Arrays are ordered collections of data, like a row of numbered lockers, each position (index) can store one value.

Creating Arrays

javascript
// Method 1: Array literal (most common)
let fruits = ["apple", "banana", "orange"];
let numbers = [1, 2, 3, 4, 5];
let mixed = [1, "hello", true, null, { name: "Test" }];

// Method 2: Array constructor
let arr1 = new Array(); // Empty array
let arr2 = new Array(5); // Array with length 5 (empty)
let arr3 = new Array(1, 2, 3); // [1, 2, 3]

// Method 3: Array.of() (ES6)
let arr4 = Array.of(5); // [5] (avoids constructor ambiguity)
let arr5 = Array.of(1, 2, 3); // [1, 2, 3]

// Method 4: Array.from() (ES6)
let str = "hello";
let chars = Array.from(str); // ["h", "e", "l", "l", "o"]

Accessing and Modifying Array Elements

javascript
let colors = ["red", "green", "blue"];

// Access elements (index starts from 0)
console.log(colors[0]); // "red"
console.log(colors[1]); // "green"
console.log(colors[2]); // "blue"

// Modify elements
colors[1] = "yellow";
console.log(colors); // ["red", "yellow", "blue"]

// Add elements
colors[3] = "purple";
console.log(colors); // ["red", "yellow", "blue", "purple"]

// Array length
console.log(colors.length); // 4

// Access the last element
console.log(colors[colors.length - 1]); // "purple"

Common Array Methods

javascript
let numbers = [1, 2, 3, 4, 5];

// Add/delete elements
numbers.push(6); // Add to end: [1, 2, 3, 4, 5, 6]
numbers.pop(); // Delete from end: [1, 2, 3, 4, 5]
numbers.unshift(0); // Add to beginning: [0, 1, 2, 3, 4, 5]
numbers.shift(); // Delete from beginning: [1, 2, 3, 4, 5]

// splice: delete/insert/replace
let arr = [1, 2, 3, 4, 5];
arr.splice(2, 1); // Delete 1 from index 2: [1, 2, 4, 5]
arr.splice(2, 0, 3); // Insert 3 at index 2: [1, 2, 3, 4, 5]
arr.splice(2, 1, 99); // Replace 1 at index 2 with 99: [1, 2, 99, 4, 5]

// slice: Extract subarray (doesn't modify original array)
let original = [1, 2, 3, 4, 5];
let sub = original.slice(1, 4); // [2, 3, 4]
console.log(original); // [1, 2, 3, 4, 5] (original array unchanged)

// concat: Merge arrays
let arr1 = [1, 2];
let arr2 = [3, 4];
let combined = arr1.concat(arr2); // [1, 2, 3, 4]

// join: Convert to string
let fruits = ["apple", "banana", "orange"];
console.log(fruits.join()); // "apple,banana,orange"
console.log(fruits.join(" - ")); // "apple - banana - orange"

// reverse: Reverse array (modifies original array)
let nums = [1, 2, 3];
nums.reverse();
console.log(nums); // [3, 2, 1]

// sort: Sort array (modifies original array)
let values = [3, 1, 4, 1, 5, 9];
values.sort();
console.log(values); // [1, 1, 3, 4, 5, 9]

// Custom sorting
values.sort((a, b) => b - a); // Descending order
console.log(values); // [9, 5, 4, 3, 1, 1]

Array Traversal

javascript
let fruits = ["apple", "banana", "orange"];

// for loop
for (let i = 0; i < fruits.length; i++) {
  console.log(fruits[i]);
}

// for...of loop (ES6, recommended)
for (let fruit of fruits) {
  console.log(fruit);
}

// forEach method
fruits.forEach(function (fruit, index) {
  console.log(index + ": " + fruit);
});

// Simplified syntax
fruits.forEach((fruit, index) => {
  console.log(`${index}: ${fruit}`);
});

Advanced Array Methods

javascript
let numbers = [1, 2, 3, 4, 5];

// map: Map transformation
let doubled = numbers.map((num) => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

// filter: Filter
let evens = numbers.filter((num) => num % 2 === 0);
console.log(evens); // [2, 4]

// reduce: Reduce
let sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // 15

// find: Find first element that meets condition
let found = numbers.find((num) => num > 3);
console.log(found); // 4

// some: Check if any element meets condition
let hasEven = numbers.some((num) => num % 2 === 0);
console.log(hasEven); // true

// every: Check if all elements meet condition
let allPositive = numbers.every((num) => num > 0);
console.log(allPositive); // true

Function Type

In JavaScript, functions are first-class objects, can be passed, assigned, and returned as values like variables.

Function Creation Methods

javascript
// Method 1: Function declaration
function greet(name) {
  return "Hello, " + name + "!";
}

// Method 2: Function expression
let sayHi = function (name) {
  return "Hi, " + name + "!";
};

// Method 3: Arrow function (ES6)
let welcome = (name) => {
  return "Welcome, " + name + "!";
};

// Arrow function simplified syntax
let hey = (name) => "Hey, " + name + "!";

// Method 4: Function constructor (not recommended)
let multiply = new Function("a", "b", "return a * b");

Functions as Values

javascript
// Function assigned to variable
let calculate = function (a, b) {
  return a + b;
};

console.log(calculate(5, 3)); // 8

// Function as parameter (callback function)
function executeOperation(a, b, operation) {
  return operation(a, b);
}

let add = (x, y) => x + y;
let multiply = (x, y) => x * y;

console.log(executeOperation(5, 3, add)); // 8
console.log(executeOperation(5, 3, multiply)); // 15

// Function as return value (higher-order function)
function createMultiplier(factor) {
  return function (number) {
    return number * factor;
  };
}

let double = createMultiplier(2);
let triple = createMultiplier(3);

console.log(double(5)); // 10
console.log(triple(5)); // 15

Other Reference Types

Date Object

javascript
// Create date object
let now = new Date();
let specificDate = new Date("2024-01-15");
let timestamp = new Date(1609459200000);

console.log(now); // Current date and time

// Date methods
console.log(now.getFullYear()); // Year
console.log(now.getMonth()); // Month (0-11)
console.log(now.getDate()); // Date (1-31)
console.log(now.getDay()); // Day of week (0-6, 0 is Sunday)
console.log(now.getHours()); // Hour
console.log(now.getMinutes()); // Minute
console.log(now.getTime()); // Timestamp (milliseconds)

RegExp Regular Expressions

javascript
// Create regular expression
let pattern1 = /hello/i; // Literal method
let pattern2 = new RegExp("world", "i"); // Constructor method

// Test match
let text = "Hello World";
console.log(/hello/i.test(text)); // true

// Find match
let email = "[email protected]";
let match = email.match(/@(.+)$/);
console.log(match[1]); // "example.com"

Value Passing vs Reference Passing

This is a key concept for understanding JavaScript:

javascript
// Basic types: value passing
function changeNum(x) {
  x = 100;
}

let num = 42;
changeNum(num);
console.log(num); // 42 (not affected)

// Reference types: reference passing
function changePerson(obj) {
  obj.name = "Changed";
}

let person = { name: "Original" };
changePerson(person);
console.log(person.name); // "Changed" (was modified!)

// But reassignment doesn't affect external
function reassignPerson(obj) {
  obj = { name: "New Object" };
}

reassignPerson(person);
console.log(person.name); // "Changed" (didn't become "New Object")

Deep Copy vs Shallow Copy

Shallow Copy

javascript
// Method 1: Spread operator
let original = { name: "Alice", age: 25 };
let copy1 = { ...original };

copy1.age = 30;
console.log(original.age); // 25 (not affected)

// Method 2: Object.assign()
let copy2 = Object.assign({}, original);

// Problem with shallow copy: nested objects are still references
let user = {
  name: "Bob",
  address: {
    city: "New York",
  },
};

let userCopy = { ...user };
userCopy.address.city = "London";
console.log(user.address.city); // "London" (was affected!)

Deep Copy

javascript
// Method 1: JSON method (simple but limited)
let original = {
  name: "Charlie",
  scores: [85, 90, 95],
};

let deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.scores[0] = 100;
console.log(original.scores[0]); // 85 (not affected)

// Method 2: Recursive implementation
function deepClone(obj) {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }

  if (Array.isArray(obj)) {
    return obj.map(deepClone);
  }

  let clone = {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key]);
    }
  }
  return clone;
}

Summary

Reference types are the core of JavaScript programming. Understanding how they work is crucial for writing high-quality code.

Key Points Review:

  • Reference types store references (addresses), not values themselves
  • Object: Key-value pair collections, the most fundamental reference type in JavaScript
  • Array: Ordered collections of values, providing rich manipulation methods
  • Function: Executable code blocks, also objects
  • Reference type comparison compares references, not values
  • When passing reference types as function parameters, a copy of the reference is passed
  • Understand the differences and application scenarios between shallow copy and deep copy
  • Basic types and reference types behave completely differently in assignment, comparison, and passing