What array methods do you know?

👨‍💻 Frontend Developer 🟡 Often Asked 🎚️ Easy
#JavaScript #Arrays #JS Basics

Brief Answer

Array methods in JavaScript can be divided into several categories: mutation methods (push(), pop(), shift(), unshift(), splice()), search methods (indexOf(), find(), includes()), iteration methods (map(), filter(), forEach(), reduce()) and transformation methods (join(), slice(), concat()). Each method has its own features and use cases.

Main categories:

  • Mutating — modify the original array
  • Non-mutating — return a new array
  • Iterative — traverse array elements
  • Search — find elements by condition

What are Array Methods

Array methods are built-in functions that allow you to perform various operations with arrays: adding, removing, searching, transforming and iterating over elements.

Why Different Methods are Needed

// Different tasks require different approaches
const numbers = [1, 2, 3, 4, 5];
 
// Adding elements
numbers.push(6); // [1, 2, 3, 4, 5, 6]
 
// Finding elements
const found = numbers.find(x => x > 3); // 4
 
// Transformation
const doubled = numbers.map(x => x * 2); // [2, 4, 6, 8, 10, 12]
 
// Filtering
const even = numbers.filter(x => x % 2 === 0); // [2, 4, 6]
 
console.log(numbers); // [1, 2, 3, 4, 5, 6]
console.log(doubled); // [2, 4, 6, 8, 10, 12]

Array Mutation Methods

1. push() — adding to the end

const fruits = ['apple', 'banana'];
 
// Adding one element
fruits.push('orange');
console.log(fruits); // ['apple', 'banana', 'orange']
 
// Adding multiple elements
fruits.push('pear', 'kiwi');
console.log(fruits); // ['apple', 'banana', 'orange', 'pear', 'kiwi']
 
// Returns new array length
const newLength = fruits.push('mango');
console.log(newLength); // 6

Features:

  • ✅ Modifies the original array
  • ✅ Returns new array length
  • ✅ Fast way to add to the end

2. pop() — removing from the end

const numbers = [1, 2, 3, 4, 5];
 
// Removing last element
const removed = numbers.pop();
console.log(removed); // 5
console.log(numbers); // [1, 2, 3, 4]
 
// Removing from empty array
const empty = [];
const result = empty.pop();
console.log(result); // undefined

Features:

  • ✅ Modifies the original array
  • ✅ Returns removed element
  • ✅ Returns undefined for empty array

3. unshift() — adding to the beginning

const colors = ['red', 'green'];
 
// Adding to the beginning
colors.unshift('blue');
console.log(colors); // ['blue', 'red', 'green']
 
// Adding multiple elements
colors.unshift('yellow', 'purple');
console.log(colors); // ['yellow', 'purple', 'blue', 'red', 'green']

Features:

  • ✅ Modifies the original array
  • ✅ Returns new length
  • ❌ Slower than push() (needs to shift elements)

4. shift() — removing from the beginning

const animals = ['cat', 'dog', 'bird'];
 
// Removing first element
const first = animals.shift();
console.log(first); // 'cat'
console.log(animals); // ['dog', 'bird']

Features:

  • ✅ Modifies the original array
  • ✅ Returns removed element
  • ❌ Slower than pop() (needs to shift elements)

5. splice() — universal modification

const letters = ['a', 'b', 'c', 'd', 'e'];
 
// Removing elements
const removed = letters.splice(1, 2); // Starting from index 1, remove 2 elements
console.log(removed); // ['b', 'c']
console.log(letters); // ['a', 'd', 'e']
 
// Adding elements
letters.splice(1, 0, 'x', 'y'); // At position 1, remove 0, add 'x', 'y'
console.log(letters); // ['a', 'x', 'y', 'd', 'e']
 
// Replacing elements
letters.splice(1, 2, 'z'); // At position 1, remove 2, add 'z'
console.log(letters); // ['a', 'z', 'd', 'e']

Features:

  • ✅ Most versatile method
  • ✅ Can remove, add and replace
  • ✅ Returns array of removed elements

Search Methods

1. indexOf() — finding index

const fruits = ['apple', 'banana', 'orange', 'banana'];
 
// Finding first occurrence
const index = fruits.indexOf('banana');
console.log(index); // 1
 
// Searching from specific position
const nextIndex = fruits.indexOf('banana', 2);
console.log(nextIndex); // 3
 
// Element not found
const notFound = fruits.indexOf('pear');
console.log(notFound); // -1

2. includes() — checking presence

const numbers = [1, 2, 3, 4, 5];
 
// Checking element presence
console.log(numbers.includes(3)); // true
console.log(numbers.includes(6)); // false
 
// Checking from specific position
console.log(numbers.includes(2, 2)); // false (search starts from index 2)

3. find() — searching by condition

const users = [
  {name: 'John', age: 25},
  {name: 'Mary', age: 30},
  {name: 'Peter', age: 35}
];
 
// Finding first element by condition
const user = users.find(u => u.age > 28);
console.log(user); // {name: 'Mary', age: 30}
 
// Element not found
const notFound = users.find(u => u.age > 40);
console.log(notFound); // undefined

4. findIndex() — finding index by condition

const scores = [85, 92, 78, 96, 88];
 
// Finding index of first element by condition
const index = scores.findIndex(score => score > 90);
console.log(index); // 1 (element 92)
 
// Element not found
const notFound = scores.findIndex(score => score > 100);
console.log(notFound); // -1

Iteration Methods

1. forEach() — executing for each element

const numbers = [1, 2, 3, 4, 5];
 
// Simple iteration
numbers.forEach(num => {
  console.log(num * 2);
});
// Output: 2, 4, 6, 8, 10
 
// With index and array
numbers.forEach((num, index, array) => {
  console.log(`Element ${num} at position ${index}`);
});

Features:

  • ✅ Doesn’t modify original array
  • ✅ Returns nothing (undefined)
  • ❌ Cannot break execution

2. map() — transforming elements

const numbers = [1, 2, 3, 4, 5];
 
// Transforming each element
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
 
// Transforming objects
const users = [{name: 'John', age: 25}, {name: 'Mary', age: 30}];
const names = users.map(user => user.name);
console.log(names); // ['John', 'Mary']
 
// With index
const withIndex = numbers.map((num, index) => `${index}: ${num}`);
console.log(withIndex); // ['0: 1', '1: 2', '2: 3', '3: 4', '4: 5']

Features:

  • ✅ Returns new array of the same length
  • ✅ Doesn’t modify original array
  • ✅ Perfect for transformations

3. filter() — filtering elements

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 
// Filtering even numbers
const even = numbers.filter(num => num % 2 === 0);
console.log(even); // [2, 4, 6, 8, 10]
 
// Filtering objects
const users = [
  {name: 'John', age: 17},
  {name: 'Mary', age: 25},
  {name: 'Peter', age: 16}
];
 
const adults = users.filter(user => user.age >= 18);
console.log(adults); // [{name: 'Mary', age: 25}]

Features:

  • ✅ Returns new array
  • ✅ Can be shorter than original
  • ✅ Doesn’t modify original array

4. reduce() — array reduction

const numbers = [1, 2, 3, 4, 5];
 
// Sum of all elements
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // 15
 
// Product
const product = numbers.reduce((acc, num) => acc * num, 1);
console.log(product); // 120
 
// Finding maximum value
const max = numbers.reduce((acc, num) => Math.max(acc, num));
console.log(max); // 5
 
// Grouping objects
const users = [
  {name: 'John', department: 'IT'},
  {name: 'Mary', department: 'HR'},
  {name: 'Peter', department: 'IT'}
];
 
const grouped = users.reduce((acc, user) => {
  if (!acc[user.department]) {
    acc[user.department] = [];
  }
  acc[user.department].push(user.name);
  return acc;
}, {});
 
console.log(grouped);
// {IT: ['John', 'Peter'], HR: ['Mary']}

Features:

  • ✅ Most powerful iteration method
  • ✅ Can return any data type
  • ✅ Has initial accumulator value

Transformation Methods

1. join() — joining into string

const words = ['Hello', 'world', 'JavaScript'];
 
// Joining with space
const sentence = words.join(' ');
console.log(sentence); // 'Hello world JavaScript'
 
// Joining with different separator
const csv = words.join(', ');
console.log(csv); // 'Hello, world, JavaScript'
 
// Without separator
const combined = words.join('');
console.log(combined); // 'HelloworldJavaScript'

2. slice() — extracting part

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 
// Extracting part of array
const part = numbers.slice(2, 5);
console.log(part); // [3, 4, 5]
 
// With negative indices
const lastThree = numbers.slice(-3);
console.log(lastThree); // [8, 9, 10]
 
// Copying entire array
const copy = numbers.slice();
console.log(copy); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

3. concat() — combining arrays

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [7, 8, 9];
 
// Combining two arrays
const combined = arr1.concat(arr2);
console.log(combined); // [1, 2, 3, 4, 5, 6]
 
// Combining multiple arrays
const all = arr1.concat(arr2, arr3);
console.log(all); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
 
// Adding individual elements
const withElements = arr1.concat(10, 11, arr2);
console.log(withElements); // [1, 2, 3, 10, 11, 4, 5, 6]

Performance Comparison

Performance Test

function performanceTest() {
  const iterations = 100000;
  const testArray = Array.from({length: 1000}, (_, i) => i);
  
  // Test 1: forEach vs for
  console.time('forEach');
  for (let i = 0; i < iterations; i++) {
    testArray.forEach(x => x * 2);
  }
  console.timeEnd('forEach');
  
  console.time('for loop');
  for (let i = 0; i < iterations; i++) {
    for (let j = 0; j < testArray.length; j++) {
      testArray[j] * 2;
    }
  }
  console.timeEnd('for loop');
  
  // Test 2: map vs for
  console.time('map');
  for (let i = 0; i < iterations; i++) {
    testArray.map(x => x * 2);
  }
  console.timeEnd('map');
}
 
performanceTest();

Results (approximate)

MethodSpeedReadabilityUsage
forFastestAveragePerformance
forEachFastExcellentSimple operations
mapAverageExcellentTransformations
filterAverageExcellentFiltering
reduceSlowGoodComplex operations

Practical Examples

1. Working with User Data

const users = [
  {id: 1, name: 'John', age: 25, active: true},
  {id: 2, name: 'Mary', age: 30, active: false},
  {id: 3, name: 'Peter', age: 35, active: true},
  {id: 4, name: 'Anna', age: 28, active: true}
];
 
// Get names of active users
const activeNames = users
  .filter(user => user.active)
  .map(user => user.name);
console.log(activeNames); // ['John', 'Peter', 'Anna']
 
// Average age of active users
const activeUsers = users.filter(user => user.active);
const averageAge = activeUsers.reduce((sum, user) => sum + user.age, 0) / activeUsers.length;
console.log(averageAge); // 29.33
 
// Find user by ID
function findUserById(id) {
  return users.find(user => user.id === id);
}
 
console.log(findUserById(2)); // {id: 2, name: 'Mary', age: 30, active: false}

2. Processing Shopping List

const products = [
  {name: 'Bread', price: 30, category: 'Bakery'},
  {name: 'Milk', price: 60, category: 'Dairy'},
  {name: 'Apples', price: 120, category: 'Fruits'},
  {name: 'Cheese', price: 200, category: 'Dairy'}
];
 
// Total cost
const total = products.reduce((sum, product) => sum + product.price, 0);
console.log(`Total cost: ${total} rub.`); // 410 rub.
 
// Grouping by categories
const byCategory = products.reduce((acc, product) => {
  if (!acc[product.category]) {
    acc[product.category] = [];
  }
  acc[product.category].push(product);
  return acc;
}, {});
 
console.log(byCategory);
 
// Expensive items (more than 100 rub.)
const expensive = products.filter(product => product.price > 100);
console.log(expensive);

3. Working with Numeric Data

const scores = [85, 92, 78, 96, 88, 73, 91, 84];
 
// Statistics
const stats = {
  min: Math.min(...scores),
  max: Math.max(...scores),
  average: scores.reduce((sum, score) => sum + score, 0) / scores.length,
  passing: scores.filter(score => score >= 80).length
};
 
console.log(stats);
// {min: 73, max: 96, average: 85.875, passing: 6}
 
// Sorting (modifies original array)
const sortedScores = [...scores].sort((a, b) => b - a);
console.log(sortedScores); // [96, 92, 91, 88, 85, 84, 78, 73]
 
// Median
function getMedian(arr) {
  const sorted = [...arr].sort((a, b) => a - b);
  const mid = Math.floor(sorted.length / 2);
  return sorted.length % 2 === 0 
    ? (sorted[mid - 1] + sorted[mid]) / 2 
    : sorted[mid];
}
 
console.log(getMedian(scores)); // 86.5

Practice Tasks

Task 1

// Given an array of numbers. Find the sum of even numbers
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 
// Your code
const evenSum = ?;
 
console.log(evenSum); // 30
Answer
const evenSum = numbers
  .filter(num => num % 2 === 0)
  .reduce((sum, num) => sum + num, 0);
 
// or
const evenSum = numbers.reduce((sum, num) => {
  return num % 2 === 0 ? sum + num : sum;
}, 0);

Task 2

// What will this code output?
const arr = [1, 2, 3];
const result1 = arr.push(4);
const result2 = arr.pop();
const result3 = arr.slice(1);
 
console.log(result1);
console.log(result2);
console.log(result3);
console.log(arr);
Answer

4, 4, [2, 3], [1, 2, 3] — push() returns new array length, pop() returns removed element, slice() returns new array, original array was modified only by push() and pop().


Task 3

// Create a function that removes duplicates from array
function removeDuplicates(arr) {
  // Your code
}
 
console.log(removeDuplicates([1, 2, 2, 3, 3, 4])); // [1, 2, 3, 4]
console.log(removeDuplicates(['a', 'b', 'a', 'c'])); // ['a', 'b', 'c']
Answer
function removeDuplicates(arr) {
  return arr.filter((item, index) => arr.indexOf(item) === index);
  
  // or with Set
  // return [...new Set(arr)];
  
  // or with reduce
  // return arr.reduce((acc, item) => {
  //   return acc.includes(item) ? acc : [...acc, item];
  // }, []);
}

Modern Features

1. Method Chaining

const users = [
  {name: 'John', age: 25, salary: 50000},
  {name: 'Mary', age: 30, salary: 70000},
  {name: 'Peter', age: 35, salary: 60000},
  {name: 'Anna', age: 28, salary: 80000}
];
 
// Complex processing in one chain
const result = users
  .filter(user => user.age >= 28) // Age from 28
  .map(user => ({...user, bonus: user.salary * 0.1})) // Add bonus
  .sort((a, b) => b.salary - a.salary) // Sort by salary
  .slice(0, 2) // Take first two
  .map(user => user.name); // Only names
 
console.log(result); // ['Anna', 'Mary']

2. Using with async/await

// Processing array of promises
const urls = [
  '/api/user/1',
  '/api/user/2',
  '/api/user/3'
];
 
// Sequential processing
async function processSequentially() {
  const results = [];
  for (const url of urls) {
    const response = await fetch(url);
    const data = await response.json();
    results.push(data);
  }
  return results;
}
 
// Parallel processing
async function processInParallel() {
  const promises = urls.map(url => fetch(url).then(r => r.json()));
  return Promise.all(promises);
}
 
// Using with map and async
async function processWithMap() {
  const results = await Promise.all(
    urls.map(async url => {
      const response = await fetch(url);
      return response.json();
    })
  );
  return results;
}

3. Modern Array Methods (ES2019+)

// flat() - flattening arrays
const nested = [[1, 2], [3, 4], [5, [6, 7]]];
console.log(nested.flat()); // [1, 2, 3, 4, 5, [6, 7]]
console.log(nested.flat(2)); // [1, 2, 3, 4, 5, 6, 7]
 
// flatMap() - map + flat
const words = ['hello world', 'how are you'];
const allWords = words.flatMap(phrase => phrase.split(' '));
console.log(allWords); // ['hello', 'world', 'how', 'are', 'you']
 
// Array.from() with mapping
const range = Array.from({length: 5}, (_, i) => i + 1);
console.log(range); // [1, 2, 3, 4, 5]
 
const doubled = Array.from([1, 2, 3], x => x * 2);
console.log(doubled); // [2, 4, 6]

Best Practices

1. Choose the Right Method

// ❌ Bad: using forEach when map is needed
const numbers = [1, 2, 3, 4, 5];
const doubled = [];
numbers.forEach(num => {
  doubled.push(num * 2);
});
 
// ✅ Good: using map for transformation
const doubled = numbers.map(num => num * 2);
 
// ❌ Bad: using map when forEach is enough
const users = [{name: 'John'}, {name: 'Mary'}];
users.map(user => console.log(user.name)); // Returns [undefined, undefined]
 
// ✅ Good: using forEach for side effects
users.forEach(user => console.log(user.name));

2. Avoid Mutations

// ❌ Bad: mutating original array
function addElement(arr, element) {
  arr.push(element);
  return arr;
}
 
// ✅ Good: returning new array
function addElement(arr, element) {
  return [...arr, element];
  // or
  // return arr.concat(element);
}
 
// ❌ Bad: mutating during iteration
const numbers = [1, 2, 3, 4, 5];
numbers.forEach((num, index) => {
  if (num % 2 === 0) {
    numbers.splice(index, 1); // Dangerous!
  }
});
 
// ✅ Good: using filter
const oddNumbers = numbers.filter(num => num % 2 !== 0);

3. Use Method Chaining Wisely

// ❌ Bad: too long chain
const result = users
  .filter(user => user.active)
  .map(user => ({...user, fullName: `${user.firstName} ${user.lastName}`}))
  .filter(user => user.age >= 18)
  .sort((a, b) => a.age - b.age)
  .slice(0, 10)
  .map(user => user.fullName)
  .join(', ');
 
// ✅ Good: breaking into logical steps
const activeAdults = users
  .filter(user => user.active && user.age >= 18);
 
const withFullNames = activeAdults
  .map(user => ({...user, fullName: `${user.firstName} ${user.lastName}`}));
 
const topTen = withFullNames
  .sort((a, b) => a.age - b.age)
  .slice(0, 10);
 
const result = topTen
  .map(user => user.fullName)
  .join(', ');

Common Mistakes

1. Confusing Mutating and Non-mutating Methods

// ❌ Mistake: thinking slice() mutates
const arr = [1, 2, 3, 4, 5];
const part = arr.slice(1, 3);
console.log(arr); // Still [1, 2, 3, 4, 5]
console.log(part); // [2, 3]
 
// ❌ Mistake: thinking sort() doesn't mutate
const numbers = [3, 1, 4, 1, 5];
const sorted = numbers.sort();
console.log(numbers); // [1, 1, 3, 4, 5] - mutated!
console.log(sorted); // [1, 1, 3, 4, 5] - same reference
 
// ✅ Correct: creating copy before sorting
const sorted = [...numbers].sort();

2. Incorrect Use of reduce()

// ❌ Bad: not returning accumulator
const sum = [1, 2, 3].reduce((acc, num) => {
  acc + num; // Missing return!
});
console.log(sum); // undefined
 
// ✅ Good: always return accumulator
const sum = [1, 2, 3].reduce((acc, num) => {
  return acc + num;
}, 0);
 
// ❌ Bad: mutating accumulator object
const grouped = items.reduce((acc, item) => {
  acc[item.category].push(item); // Error if category doesn't exist
  return acc;
}, {});
 
// ✅ Good: safe object mutation
const grouped = items.reduce((acc, item) => {
  if (!acc[item.category]) {
    acc[item.category] = [];
  }
  acc[item.category].push(item);
  return acc;
}, {});

3. Performance Issues

// ❌ Bad: multiple iterations
const users = getUsers(); // Large array
const activeUsers = users.filter(user => user.active);
const adultUsers = activeUsers.filter(user => user.age >= 18);
const userNames = adultUsers.map(user => user.name);
 
// ✅ Good: single iteration
const userNames = users
  .filter(user => user.active && user.age >= 18)
  .map(user => user.name);
 
// ❌ Bad: using find() in loop
const userIds = [1, 2, 3, 4, 5];
const users = [];
for (const id of userIds) {
  const user = allUsers.find(u => u.id === id); // O(n) for each iteration
  if (user) users.push(user);
}
 
// ✅ Good: creating lookup map
const userMap = new Map(allUsers.map(user => [user.id, user]));
const users = userIds
  .map(id => userMap.get(id))
  .filter(Boolean);

Summary

Array methods in JavaScript provide powerful tools for working with data. Key points:

Method Categories:

  • Mutating: push(), pop(), shift(), unshift(), splice(), sort(), reverse()
  • Non-mutating: map(), filter(), slice(), concat(), join()
  • Search: find(), findIndex(), indexOf(), includes()
  • Iteration: forEach(), map(), filter(), reduce()

Best Practices:

  • Choose the right method for the task
  • Prefer immutable operations
  • Use method chaining wisely
  • Consider performance for large datasets
  • Always return accumulator in reduce()

Performance:

  • for loops are fastest for simple operations
  • Array methods provide better readability
  • Avoid multiple iterations over large arrays
  • Use Map for frequent lookups

Modern Features:

  • Method chaining for complex transformations
  • flat() and flatMap() for nested arrays
  • Array.from() for array creation
  • Async operations with Promise.all()

Mastering array methods is essential for effective JavaScript development and functional programming patterns.


Want more interview preparation articles? Subscribe to EasyAdvice, bookmark the site and improve yourself every day 💪