What Are Arrays?
Arrays are ordered collections of values that can hold data of any type. Think of an array as an organized list of items, like a shopping list, a playlist of songs, or a collection of books on a shelf.
In JavaScript, arrays are special objects where the keys are automatically managed numeric indices, starting from 0.
Unlike arrays in some other programming languages, JavaScript arrays:
- Can store mixed data types (numbers, strings, objects, even other arrays)
- Are dynamically sized (they grow and shrink as needed)
- Have zero-based indexing (the first element is at index 0)
Ways to Create Arrays
JavaScript provides several methods to create arrays, each with specific use cases.
Array Literal Notation
The most common and straightforward way to create an array is using square brackets:
// Empty array
const emptyArray = [];
// Array with elements
const fruits = ["Apple", "Banana", "Cherry"];
// Array with mixed types
const mixed = [42, "hello", true, { name: "Object" }, [1, 2, 3]];
console.log(fruits.length); // 3
console.log(mixed.length); // 5
Array Constructor
You can create arrays using the Array() constructor, but be careful with its behavior:
// Empty array
const emptyArray = new Array(); // []
// Array with elements
const colors = new Array("Red", "Green", "Blue"); // ["Red", "Green", "Blue"]
// CAUTION: This creates an array with 5 empty slots, not an array containing the number 5
const sparseArray = new Array(5); // [ <5 empty items> ]
console.log(sparseArray.length); // 5
// To create an array with a single numeric element, use Array.of()
const singleItemArray = Array.of(5); // [5]
console.log(singleItemArray.length); // 1
Array.of() Method
The Array.of() method creates a new array from a variable number of arguments, regardless of type or number:
const numbers = Array.of(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
const singleItem = Array.of(42); // [42]
const mixed = Array.of("hello", true, 3.14); // ["hello", true, 3.14]
Array.from() Method
The Array.from() method creates a new array from an array-like or iterable object:
// From a string
const chars = Array.from("Hello"); // ["H", "e", "l", "l", "o"]
// From a Set
const uniqueNumbers = Array.from(new Set([1, 2, 2, 3, 1, 4])); // [1, 2, 3, 4]
// With a mapping function (2nd argument)
const doubled = Array.from([1, 2, 3], x => x * 2); // [2, 4, 6]
// From array-like objects (objects with length property and indexed elements)
function getArgs() {
return Array.from(arguments);
}
console.log(getArgs(1, 'a', true)); // [1, "a", true]
// Creating an array of numbers from 1 to 5
const range = Array.from({ length: 5 }, (_, i) => i + 1); // [1, 2, 3, 4, 5]
Spread Operator
The spread operator (...) can create a new array from existing iterable objects:
// From another array (creates a shallow copy)
const original = [1, 2, 3];
const copy = [...original]; // [1, 2, 3]
// Combine arrays
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const combined = [...array1, ...array2]; // [1, 2, 3, 4, 5, 6]
// Spread with additional elements
const extended = [0, ...array1, 4]; // [0, 1, 2, 3, 4]
// From other iterables
const setToArray = [...new Set([1, 2, 2, 3, 4])]; // [1, 2, 3, 4]
const strToArray = [..."hello"]; // ["h", "e", "l", "l", "o"]
Accessing Array Elements
JavaScript provides several ways to access and manipulate elements in an array.
Index-Based Access
The most basic way to access elements is using bracket notation with the element's index:
const fruits = ["Apple", "Banana", "Cherry", "Date", "Elderberry"];
// Access by index (zero-based)
console.log(fruits[0]); // "Apple"
console.log(fruits[2]); // "Cherry"
// Last element
console.log(fruits[fruits.length - 1]); // "Elderberry"
// Using negative indices (ES2022 feature: at() method)
console.log(fruits.at(-1)); // "Elderberry" (last element)
console.log(fruits.at(-2)); // "Date" (second to last element)
// Out of bounds
console.log(fruits[10]); // undefined (doesn't throw an error)
Destructuring Assignment
ES6 introduced destructuring, a powerful way to extract values from arrays:
const colors = ["Red", "Green", "Blue", "Yellow", "Purple"];
// Basic destructuring
const [first, second, third] = colors;
console.log(first); // "Red"
console.log(second); // "Green"
console.log(third); // "Blue"
// Skip elements
const [primary, , tertiary] = colors;
console.log(primary); // "Red"
console.log(tertiary); // "Blue"
// Rest pattern
const [head, ...tail] = colors;
console.log(head); // "Red"
console.log(tail); // ["Green", "Blue", "Yellow", "Purple"]
// Default values
const [a, b, c = "Default"] = ["One", "Two"];
console.log(a); // "One"
console.log(b); // "Two"
console.log(c); // "Default"
// Swapping variables
let x = 1, y = 2;
[x, y] = [y, x];
console.log(x, y); // 2 1
Nested Array Access
For multi-dimensional arrays (arrays within arrays), we can use chained bracket notation:
// 2D array (matrix)
const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
console.log(matrix[1][2]); // 6 (row 1, column 2)
// Nested destructuring
const [[a1, a2], [b1, b2]] = [[1, 2], [3, 4], [5, 6]];
console.log(a1, a2, b1, b2); // 1 2 3 4
Modifying Arrays
JavaScript arrays are mutable, meaning you can change their contents after creation.
Assigning Elements
const fruits = ["Apple", "Banana", "Cherry"];
// Change existing element
fruits[1] = "Blueberry";
console.log(fruits); // ["Apple", "Blueberry", "Cherry"]
// Add element at specific index
fruits[3] = "Date";
console.log(fruits); // ["Apple", "Blueberry", "Cherry", "Date"]
// CAUTION: Creating sparse arrays
fruits[6] = "Fig";
console.log(fruits); // ["Apple", "Blueberry", "Cherry", "Date", empty × 2, "Fig"]
console.log(fruits.length); // 7
Array Properties
The length property is special - it's automatically updated when the array changes, and can be manually modified to resize the array:
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.length); // 5
// Truncate an array by reducing length
numbers.length = 3;
console.log(numbers); // [1, 2, 3]
// Extend an array by increasing length (creates empty slots)
numbers.length = 6;
console.log(numbers); // [1, 2, 3, empty × 3]
Array Sparse vs. Dense
A key concept to understand is the difference between sparse and dense arrays in JavaScript:
Dense Arrays
Dense arrays have elements at every index from 0 up to length-1 with no gaps:
const dense = [1, 2, 3, 4, 5]; // Every index is filled
Sparse Arrays
Sparse arrays have "empty slots" or "holes" where no element exists at a particular index:
// Creating sparse arrays
const sparse1 = new Array(5); // [ <5 empty items> ]
const sparse2 = [];
sparse2[0] = 1;
sparse2[2] = 3; // [1, <1 empty item>, 3]
// Deleting elements creates holes
const arr = [1, 2, 3, 4];
delete arr[1]; // [1, <1 empty item>, 3, 4]
// How empty slots behave
const sparse = [1, , 3, 4];
console.log(sparse.length); // 4
console.log(0 in sparse); // true (index 0 exists)
console.log(1 in sparse); // false (index 1 doesn't exist)
// CAUTION: Iteration behaves differently with empty slots
sparse.forEach(item => console.log(item)); // 1, 3, 4 (skips empty slots)
console.log(sparse.map(x => x * 2)); // [2, <1 empty item>, 6, 8]
// But for...in and for...of behave differently
for (const index in sparse) {
console.log(index); // "0", "2", "3" (skips the empty slot)
}
for (const item of sparse) {
console.log(item); // 1, undefined, 3, 4 (undefined for the empty slot)
}
Best practice is to use dense arrays whenever possible to avoid unexpected behaviors with various array methods.
Checking if a Variable is an Array
Since JavaScript arrays are objects, the typeof operator doesn't help identify arrays:
const arr = [1, 2, 3];
console.log(typeof arr); // "object" (not very helpful)
// Proper ways to check if something is an array
console.log(Array.isArray(arr)); // true (recommended method)
// Alternative (older method)
console.log(arr instanceof Array); // true
// Yet another way (less recommended)
console.log(Object.prototype.toString.call(arr) === '[object Array]'); // true
Arrays in the Real World
Data Structures
Arrays form the building blocks of many common data structures:
// Stack implementation using array
class Stack {
constructor() {
this.items = [];
}
push(item) {
this.items.push(item);
}
pop() {
if (this.isEmpty()) return null;
return this.items.pop();
}
peek() {
if (this.isEmpty()) return null;
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length === 0;
}
size() {
return this.items.length;
}
}
// Using the stack
const browserHistory = new Stack();
browserHistory.push("homepage.html");
browserHistory.push("product.html");
browserHistory.push("checkout.html");
console.log(browserHistory.peek()); // "checkout.html"
console.log(browserHistory.pop()); // "checkout.html"
console.log(browserHistory.peek()); // "product.html"
Practical Array Use Cases
// UI Component: Carousel implementation
class ImageCarousel {
constructor(images) {
this.images = Array.isArray(images) ? images : [];
this.currentIndex = 0;
}
addImage(url) {
this.images.push(url);
}
removeImage(url) {
const index = this.images.indexOf(url);
if (index !== -1) {
this.images.splice(index, 1);
// Adjust currentIndex if needed
if (this.currentIndex >= this.images.length) {
this.currentIndex = Math.max(0, this.images.length - 1);
}
}
}
getCurrentImage() {
return this.images[this.currentIndex];
}
next() {
this.currentIndex = (this.currentIndex + 1) % this.images.length;
return this.getCurrentImage();
}
previous() {
this.currentIndex = (this.currentIndex - 1 + this.images.length) % this.images.length;
return this.getCurrentImage();
}
get length() {
return this.images.length;
}
}
// Usage
const carousel = new ImageCarousel([
"image1.jpg",
"image2.jpg",
"image3.jpg"
]);
console.log(carousel.getCurrentImage()); // "image1.jpg"
console.log(carousel.next()); // "image2.jpg"
console.log(carousel.next()); // "image3.jpg"
console.log(carousel.next()); // "image1.jpg" (wraps around)
console.log(carousel.previous()); // "image3.jpg"
Common Array Patterns
Creating Ranges
// Create an array with numbers 1 to 10
const range1 = Array.from({ length: 10 }, (_, i) => i + 1);
console.log(range1); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// Create an array with specific range
function createRange(start, end) {
return Array.from({ length: end - start + 1 }, (_, i) => start + i);
}
console.log(createRange(5, 10)); // [5, 6, 7, 8, 9, 10]
Filling Arrays
// Fill an array with the same value
const zeros = new Array(5).fill(0);
console.log(zeros); // [0, 0, 0, 0, 0]
// Create a matrix (2D array) with zeros
function createMatrix(rows, cols, defaultValue = 0) {
return Array.from({ length: rows }, () =>
Array.from({ length: cols }, () => defaultValue)
);
}
const grid = createMatrix(3, 4);
console.log(grid);
// [
// [0, 0, 0, 0],
// [0, 0, 0, 0],
// [0, 0, 0, 0]
// ]
Converting Arrays
// Convert array-like objects to arrays
function sum() {
// arguments is array-like but not an array
const args = Array.from(arguments);
return args.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
// Convert arrays to other data structures
const arr = [1, 2, 3, 2, 1, 4];
// To Set (removes duplicates)
const uniqueSet = new Set(arr);
console.log(uniqueSet); // Set(4) {1, 2, 3, 4}
// Back to array
const uniqueArray = [...uniqueSet];
console.log(uniqueArray); // [1, 2, 3, 4]
// To Object with indices as keys
const obj = Object.assign({}, arr);
console.log(obj); // {0: 1, 1: 2, 2: 3, 3: 2, 4: 1, 5: 4}
Multi-Dimensional Arrays
JavaScript doesn't have true multi-dimensional arrays, but we can create arrays of arrays:
// 2D array (matrix)
const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
// Accessing elements
console.log(matrix[1][2]); // 6 (row 1, column 2)
// Iterating over a 2D array
for (let i = 0; i < matrix.length; i++) {
for (let j = 0; j < matrix[i].length; j++) {
console.log(`matrix[${i}][${j}] = ${matrix[i][j]}`);
}
}
// Using modern iteration
matrix.forEach((row, i) => {
row.forEach((val, j) => {
console.log(`matrix[${i}][${j}] = ${val}`);
});
});
// 3D array
const cube = [
[
[1, 2],
[3, 4]
],
[
[5, 6],
[7, 8]
]
];
console.log(cube[1][0][1]); // 6
Multi-dimensional arrays are commonly used for grids, game boards, matrices, and other structured data.
Performance Considerations
Arrays in JavaScript are optimized for certain operations, but have trade-offs:
- Fast operations: Access by index, operations at the end (push/pop)
- Slow operations: Insertions/deletions at the beginning (shift/unshift), searching without index
// Performance example: adding items
const arr = [];
console.time('push');
for (let i = 0; i < 1000000; i++) {
arr.push(i); // Fast - adds to the end
}
console.timeEnd('push');
const arr2 = [];
console.time('unshift');
for (let i = 0; i < 10000; i++) { // Only 10000, not 1000000!
arr2.unshift(i); // Slow - adds to the beginning and shifts all elements
}
console.timeEnd('unshift');
// For larger collections where you need frequent insertions/deletions
// at both ends, consider using specialized data structures like a
// linked list or a double-ended queue instead of arrays
Practice Activities
Activity 1: Array Creation Challenge
Create arrays using different methods (literal, Array.from, spread operator) to represent a deck of cards with suits and values.
Activity 2: Multi-dimensional Array Manipulation
Create a tic-tac-toe game board as a 3x3 matrix and write functions to place X or O marks and check for win conditions.
Activity 3: Array Transformation
Write a function that takes an array of numbers and converts it into a histogram representation using nested arrays or objects.
Summary
In this lecture, we've explored:
- What arrays are and their fundamental characteristics in JavaScript
- Various ways to create arrays: literals, constructors, and ES6 methods
- How to access array elements using indices and destructuring
- Methods to modify arrays and the importance of the length property
- The distinction between sparse and dense arrays
- Working with multi-dimensional arrays
- Real-world use cases and performance considerations
Arrays are incredibly versatile data structures that form the backbone of many JavaScript applications. Understanding how to effectively create, access, and manipulate arrays is essential for becoming a proficient JavaScript developer.