π¨ JavaScript Array Basics
Index: Basics Index | Parent: JS Array Index
1. What is a JavaScript Array?
A JavaScript array is a dynamic, ordered list of values. Unlike low-level languages, JS arrays:
- Can hold any type (numbers, strings, objects, mixed)
- Resize automatically β no fixed size
- Are actually objects under the hood (
typeof [] === 'object') - Are zero-indexed
Memory Model (conceptual):
Index: [0] [1] [2] [3] [4]
Value: [10] [20] [30] [40] [50]
β first β last (arr.length - 1)
Key Properties:
- Access by index β O(1)
- Insert/Delete at end β O(1)
- Insert/Delete at beginning/middle β O(n) (shifts elements)
2. Creating Arrays
// 1. Array literal (most common)
const arr = [10, 20, 30, 40, 50];
// 2. Array constructor
const arr2 = new Array(5); // [empty Γ 5]
const arr3 = new Array(1, 2, 3); // [1, 2, 3]
// 3. Array.of() β avoids Array(n) single-arg ambiguity
const arr4 = Array.of(5); // [5] (not [empty Γ 5])
const arr5 = Array.of(1, 2, 3); // [1, 2, 3]
// 4. Array.from() β from iterable or array-like
const arr6 = Array.from('hello'); // ['h','e','l','l','o']
const arr7 = Array.from({length: 5}, (_, i) => i); // [0,1,2,3,4]
const arr8 = Array.from(new Set([1,2,2,3])); // [1,2,3]
// 5. Spread from another iterable
const set = new Set([1, 2, 3]);
const arr9 = [...set]; // [1, 2, 3]
// Pre-fill array
const zeros = new Array(5).fill(0); // [0,0,0,0,0]
const matrix = Array.from({length:3}, () => new Array(3).fill(0));
// [[0,0,0],[0,0,0],[0,0,0]]
3. Accessing Elements
const fruits = ['apple', 'banana', 'cherry', 'date'];
// By index
console.log(fruits[0]); // 'apple'
console.log(fruits[3]); // 'date'
console.log(fruits[-1]); // undefined (JS doesn't support negative index directly)
// at() β supports negative indexing (ES2022)
console.log(fruits.at(-1)); // 'date' β last element
console.log(fruits.at(-2)); // 'cherry'
// Array destructuring
const [first, second, ...rest] = fruits;
console.log(first); // 'apple'
console.log(second); // 'banana'
console.log(rest); // ['cherry', 'date']
// Skip elements
const [,, third] = fruits;
console.log(third); // 'cherry'
// Swap two variables (no temp variable needed)
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 2 1
// Default values in destructuring
const [x = 0, y = 0, z = 0] = [10, 20];
console.log(x, y, z); // 10 20 0
4. Mutating Arrays
const arr = [1, 2, 3];
// ββ End operations O(1) ββββββββββββββββββββββββββ
arr.push(4); // [1,2,3,4] β add to end
arr.push(5, 6); // [1,2,3,4,5,6] β multiple
const last = arr.pop(); // removes & returns last: 6
// ββ Start operations O(n) ββββββββββββββββββββββββ
arr.unshift(0); // [0,1,2,3,4,5] β add to start
const first = arr.shift(); // removes & returns first: 0
// ββ Middle operations: splice ββββββββββββββββββββ
// splice(startIndex, deleteCount, ...itemsToInsert)
arr.splice(2, 0, 99); // insert 99 at index 2, delete 0
// arr = [1,2,99,3,4,5]
arr.splice(2, 1); // remove 1 element at index 2
// arr = [1,2,3,4,5]
arr.splice(1, 2, 10, 20); // replace 2 elements starting at 1
// arr = [1,10,20,4,5]
// ββ Reverse & sort βββββββββββββββββββββββββββββββ
arr.reverse(); // mutates in place!
arr.sort(); // mutates in place β CAUTION: sorts as strings!
5. Spread & Rest Operator
// ββ SPREAD βββββββββββββββββββββββββββββββββββββββ
// Clone an array (shallow)
const original = [1, 2, 3];
const clone = [...original]; // new array, not a reference
clone.push(4);
console.log(original); // [1,2,3] β unchanged
// Merge arrays
const a = [1, 2];
const b = [3, 4];
const merged = [...a, ...b]; // [1,2,3,4]
// Pass array as function arguments
function sum(x, y, z) { return x + y + z; }
const nums = [1, 2, 3];
console.log(sum(...nums)); // 6
// Add element without mutation
const arr = [1, 2, 3];
const newArr = [...arr, 4]; // [1,2,3,4]
const newFront = [0, ...arr]; // [0,1,2,3]
// ββ REST (collect remaining) ββββββββββββββββββββββ
function first3(...args) {
const [a, b, c, ...others] = args;
return { first: [a,b,c], rest: others };
}
console.log(first3(1,2,3,4,5));
// { first: [1,2,3], rest: [4,5] }
6. Multidimensional Arrays
// 2D array (matrix)
const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
// Access: matrix[row][col]
console.log(matrix[1][2]); // 6
// Iterate over 2D array
for (let r = 0; r < matrix.length; r++) {
for (let c = 0; c < matrix[r].length; c++) {
process.stdout.write(matrix[r][c] + ' ');
}
console.log();
}
// Using forEach
matrix.forEach(row => console.log(row.join(' ')));
// Create NxM matrix filled with zeros
const rows = 3, cols = 4;
const grid = Array.from({length: rows}, () => new Array(cols).fill(0));
// Common mistake: DON'T do this
const wrong = new Array(3).fill([]); // all rows share SAME array reference!
wrong[0].push(1);
console.log(wrong); // [[1],[1],[1]] β BUG!
// Correct way
const correct = Array.from({length: 3}, () => []);
7. Common Mistakes
// ββ 1. Sorting numbers without comparator βββββββββ
[10, 9, 2, 100, 21].sort();
// [10, 100, 2, 21, 9] β WRONG! sorts as strings
[10, 9, 2, 100, 21].sort((a, b) => a - b);
// [2, 9, 10, 21, 100] β correct
// ββ 2. Shallow copy vs deep copy βββββββββββββββββ
const obj = [{a: 1}, {b: 2}];
const shallow = [...obj];
shallow[0].a = 99;
console.log(obj[0].a); // 99 β original mutated!
// Deep clone (simple):
const deep = JSON.parse(JSON.stringify(obj));
// ββ 3. Reference equality βββββββββββββββββββββββββ
console.log([] === []); // false β different references
console.log([1,2] == [1,2]); // false
// ββ 4. Holes in arrays ββββββββββββββββββββββββββββ
const arr = [1,,3]; // arr[1] is undefined (hole)
arr.length; // 3
// ββ 5. forEach has no return / break ββββββββββββββ
const result = [1,2,3].forEach(x => x * 2); // result is undefined!
// Use .map() if you need return values
const mapped = [1,2,3].map(x => x * 2); // [2,4,6]
// ββ 6. Off-by-one βββββββββββββββββββββββββββββββββ
const arr2 = [10, 20, 30];
// last index is arr2.length - 1 = 2
// arr2[arr2.length] = undefined β common bug
8. Interview Questions
Q1. Reverse an Array [E][FB]
π§ How to Approach This
Step 1 β Recognize the pattern:
Reverse = swap elements from both ends working inward β two pointers (opposite direction).
Step 2 β Brute force:
Create new array and copy in reverse β O(n) space. Interviewer often wants O(1) space.
Step 3 β Optimal insight:
Two pointers L=0, R=n-1. Swap, then L++, R--. Stop when L >= R.
Step 4 β JS shortcut:
[...arr].reverse()for non-mutating reverse (spread to avoid mutating original).Step 5 β Edge cases:
- Empty array: L >= R immediately, nothing to do
- Odd length: middle stays in place
Way of Thinking: Use two pointers β one at start, one at end. Swap and move toward center. O(n) time, O(1) space.
function reverseArray(arr) {
let left = 0, right = arr.length - 1;
while (left < right) {
[arr[left], arr[right]] = [arr[right], arr[left]]; // destructuring swap
left++;
right--;
}
return arr;
}
// One-liner (non-mutating)
const reversed = [...arr].reverse();
console.log(reverseArray([1,2,3,4,5])); // [5,4,3,2,1]
Q2. Find Max and Min [E][FB]
π§ How to Approach This
Step 1 β Recognize the pattern:
Single-pass scan tracking two running values.
Step 2 β Key insight:
Initialize max=-Infinity, min=Infinity. Each element either updates max, updates min, or does nothing. One O(n) pass handles both.
Step 3 β JS shortcuts:
Math.max(...arr)works for small arrays. For large arrays (>100K elements), spread can cause stack overflow β usereduceinstead.Step 4 β Edge cases:
- Single element: max = min = that element
- All negatives: max will be a negative number
Way of Thinking: Single pass, track max/min variables. OR use Math.max(...arr) for small arrays.
function findMaxMin(arr) {
let max = -Infinity, min = Infinity;
for (const num of arr) {
if (num > max) max = num;
if (num < min) min = num;
}
return { max, min };
}
// One-liners
const max = Math.max(...arr); // spread into Math.max
const min = Math.min(...arr);
// β spread can cause stack overflow for very large arrays
// Safe alternative:
const safeMax = arr.reduce((a, b) => a > b ? a : b);
console.log(findMaxMin([3, 1, 4, 1, 5, 9, 2])); // { max: 9, min: 1 }
Q3. Count Occurrences of Each Element [E][FB]
π§ How to Approach This
Step 1 β Recognize the pattern:
Frequency counting = Map or plain object as hashmap. O(n) time.
Step 2 β Key insight:
For each element: if already in map, increment; otherwise initialize to 1.
map.get(key) || 0handles missing keys cleanly.Step 3 β Follow-up questions to anticipate:
"Most frequent element" β find entry with max value in map.
"Majority element (>n/2)" β Boyer-Moore Voting Algorithm.
Step 4 β Edge cases:
- Mixed types: Map handles
1and"1"as different keys (unlike plain objects)
Way of Thinking: Use a Map for frequency counting. Map preserves insertion order and handles any key type.
function countOccurrences(arr) {
const freq = new Map();
for (const item of arr) {
freq.set(item, (freq.get(item) || 0) + 1);
}
return freq;
}
// Using reduce
function countOccurrencesReduce(arr) {
return arr.reduce((acc, item) => {
acc[item] = (acc[item] || 0) + 1;
return acc;
}, {});
}
console.log(countOccurrences([1,2,2,3,3,3]));
// Map { 1 => 1, 2 => 2, 3 => 3 }
Q4. Remove Duplicates [E][FB]
π§ How to Approach This
Step 1 β Choose right approach for context:
- Unsorted, need new array:
[...new Set(arr)]β O(n) time, O(n) space- Sorted, in-place: two-pointer (slow/fast) β O(n) time, O(1) space
Step 2 β Set approach:
Setautomatically deduplicates. Spread back into array to preserve array type.Step 3 β Two-pointer in-place (sorted):
slow = write pointer, fast = scan pointer. Write nums[fast] when it differs from previous.
Step 4 β Edge cases:
- Empty array: return []
- All duplicates: result has one element
Way of Thinking: Set automatically stores unique values. Spread back into array.
// Method 1: Set (simplest)
function removeDuplicates(arr) {
return [...new Set(arr)];
}
// Method 2: filter + indexOf
function removeDuplicates2(arr) {
return arr.filter((item, index) => arr.indexOf(item) === index);
}
// Method 3: In-place for sorted array (two pointers)
function removeDuplicatesSorted(nums) {
let k = 0;
for (let i = 0; i < nums.length; i++) {
if (i === 0 || nums[i] !== nums[i - 1]) {
nums[k++] = nums[i];
}
}
return k; // return new length
}
console.log(removeDuplicates([1,2,2,3,3,3,4])); // [1,2,3,4]
Q5. Check if Array is Sorted [E]
π§ How to Approach This
Step 1 β Recognize the pattern:
Single-pass adjacent comparison. Return false on first violation.
Step 2 β Key insight:
Only need to compare arr[i] vs arr[i-1] (or arr[i+1]). If any adjacent pair is out of order, the whole array is not sorted. Short-circuit as soon as you find one violation.
Step 3 β Elegant JS:
arr.every((v, i) => i === 0 || arr[i-1] <= v)β concise and readable.Step 4 β Edge cases:
- Empty or single element: always sorted
- Duplicate adjacent values: still sorted (equal is fine)
Way of Thinking: Compare each adjacent pair. If any pair is out of order, return false.
function isSorted(arr, ascending = true) {
for (let i = 1; i < arr.length; i++) {
if (ascending && arr[i] < arr[i-1]) return false;
if (!ascending && arr[i] > arr[i-1]) return false;
}
return true;
}
// Using every (elegant)
const isSortedAsc = arr => arr.every((v, i) => i === 0 || arr[i-1] <= v);
const isSortedDesc = arr => arr.every((v, i) => i === 0 || arr[i-1] >= v);
console.log(isSorted([1,2,3,4,5])); // true
console.log(isSorted([1,3,2,4,5])); // false
console.log(isSorted([5,4,3,2], false)); // true
Q6. Rotate Array by K Positions [M][FB]
π§ How to Approach This
Step 1 β Recognize the pattern:
Rotate right by k = last k elements move to front. "Reverse trick" for O(1) space.
Step 2 β Brute force:
Slice and concatenate:
[...arr.slice(-k), ...arr.slice(0,-k)]β O(n) space, perfectly fine in JS interviews.Step 3 β Optimal: reverse trick O(1) space:
1. Reverse all elements
2. Reverse first k elements
3. Reverse remaining elements
Result is rotated right by k.
Step 4 β Always do
k = k % nfirst to handle k > n.Step 5 β Edge cases:
- k = 0 or k = n: no change
- k > n: modulo handles it
Way of Thinking: Reverse trick: reverse entire array β reverse first k β reverse rest k..n. Handles k > n with modulo.
function rotate(nums, k) {
k = k % nums.length; // handle k > length
if (k === 0) return nums;
function reverse(arr, left, right) {
while (left < right) {
[arr[left], arr[right]] = [arr[right], arr[left]];
left++;
right--;
}
}
reverse(nums, 0, nums.length - 1); // reverse all
reverse(nums, 0, k - 1); // reverse first k
reverse(nums, k, nums.length - 1); // reverse rest
return nums;
}
// One-liner (uses extra space)
const rotateFn = (arr, k) => {
k = k % arr.length;
return [...arr.slice(-k), ...arr.slice(0, -k)];
};
console.log(rotate([1,2,3,4,5,6,7], 3)); // [5,6,7,1,2,3,4]