포스트

JavaScript Array Methods 완벽 가이드 - 실무 필수 배열 메서드 정복하기

JavaScript 배열 메서드 완벽 정리. map, filter, reduce, forEach, find 등 실무에서 필수적인 배열 조작 메서드를 실전 예제와 함께 마스터합니다.

JavaScript Array Methods 완벽 가이드 - 실무 필수 배열 메서드 정복하기

들어가며

JavaScript 배열(Array)은 가장 자주 사용하는 자료구조 중 하나입니다.

배열을 효율적으로 다루는 방법을 알면 코드의 가독성과 생산성이 크게 향상됩니다. 특히 함수형 프로그래밍 스타일의 배열 메서드를 활용하면 더 간결하고 읽기 쉬운 코드를 작성할 수 있습니다.

배열 메서드는 대부분 Arrow Function과 함께 콜백 함수로 사용됩니다!

콜백 함수(Callback Function)란?

배열 메서드를 이해하기 전에 먼저 콜백 함수의 개념을 알아야 합니다.

1
2
3
4
5
6
7
8
9
10
11
// 콜백 함수: 다른 함수의 인자로 전달되는 함수
function greeting(name) {
  console.log(`Hello, ${name}!`);
}

function processUserInput(callback) {
  const name = 'John';
  callback(name);  // greeting 함수를 콜백으로 실행
}

processUserInput(greeting);  // 'Hello, John!'

콜백 함수는 인자로 전달되어 특정 시점에 호출되는 함수입니다.

배열 순회 메서드

forEach() - 기본 반복문

forEachfor문을 대체하는 배열 반복 메서드입니다.

기본 문법

1
2
3
array.forEach((element, index, array) => {
  // 각 요소에 대해 실행할 코드
});

매개변수:

  • element: 현재 처리 중인 요소
  • index: 현재 요소의 인덱스 (선택)
  • array: 원본 배열 (선택)

기본 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const numbers = [1, 2, 3, 4, 5];

// 각 요소 출력
numbers.forEach(num => {
  console.log(num);
});
// 1, 2, 3, 4, 5

// 인덱스와 함께 출력
numbers.forEach((num, index) => {
  console.log(`Index ${index}: ${num}`);
});
// Index 0: 1
// Index 1: 2
// ...

실전 예제

1
2
3
4
5
6
7
8
9
10
11
const names = ['Alice', 'Bob', 'Charlie', 'David'];
const startsWithA = [];

// 'A'로 시작하는 이름 필터링
names.forEach(name => {
  if (name.startsWith('A')) {
    startsWithA.push(name);
  }
});

console.log(startsWithA);  // ['Alice']

forEach의 특징

특징설명
반환값undefined (아무것도 반환하지 않음)
중단return으로 현재 반복만 건너뜀 (break 불가)
용도각 요소에 대해 부수 효과(Side Effect) 수행
1
2
3
4
5
6
7
8
9
10
11
12
// 조기 종료 예제
const arr = ['a', 'b', 'c', 'd'];
let foundC = false;

arr.forEach(el => {
  if (el === 'c') {
    foundC = true;
    return;  // 현재 반복만 종료, 전체 루프는 계속
  }
  console.log(el);
});
// 출력: 'a', 'b', 'd'

⚠️ forEachbreakcontinue를 사용할 수 없습니다. 조기 종료가 필요하면 for...of를 사용하세요!

map() - 배열 변환

map은 배열의 각 요소를 변환하여 새로운 배열을 반환합니다.

기본 문법

1
2
3
const newArray = array.map((element, index, array) => {
  return transformedElement;
});

기본 예제

1
2
3
4
5
6
7
8
const numbers = [1, 2, 3, 4, 5];

// 각 요소를 제곱
const squares = numbers.map(num => num * num);
console.log(squares);  // [1, 4, 9, 16, 25]

// 원본 배열은 변경되지 않음
console.log(numbers);  // [1, 2, 3, 4, 5]

실전 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 사용자 데이터에서 이름만 추출
const users = [
  { id: 1, name: 'Alice', age: 25 },
  { id: 2, name: 'Bob', age: 30 },
  { id: 3, name: 'Charlie', age: 35 }
];

const names = users.map(user => user.name);
console.log(names);  // ['Alice', 'Bob', 'Charlie']

// 객체 변환
const userSummaries = users.map(user => ({
  name: user.name,
  isAdult: user.age >= 18
}));
console.log(userSummaries);
// [
//   { name: 'Alice', isAdult: true },
//   { name: 'Bob', isAdult: true },
//   { name: 'Charlie', isAdult: true }
// ]

map vs forEach 비교

1
2
3
4
5
6
7
8
9
const arr = [1, 2, 3];

// forEach: 반환값 없음
const result1 = arr.forEach(x => x * 2);
console.log(result1);  // undefined

// map: 새 배열 반환
const result2 = arr.map(x => x * 2);
console.log(result2);  // [2, 4, 6]
구분forEachmap
반환값undefined새 배열
용도부수 효과 수행배열 변환
체이닝불가능가능

💡 선택 기준: 새로운 배열이 필요하면 map, 단순 반복 작업이면 forEach!

배열 필터링 메서드

filter() - 조건에 맞는 요소만 추출

filter는 조건을 만족하는 요소들로만 구성된 새 배열을 반환합니다.

기본 문법

1
2
3
const newArray = array.filter((element, index, array) => {
  return condition;  // true면 포함, false면 제외
});

기본 예제

1
2
3
4
5
6
7
8
9
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// 짝수만 필터링
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers);  // [2, 4, 6, 8, 10]

// 5보다 큰 수
const greaterThanFive = numbers.filter(num => num > 5);
console.log(greaterThanFive);  // [6, 7, 8, 9, 10]

실전 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const products = [
  { name: 'Laptop', price: 1200, inStock: true },
  { name: 'Phone', price: 800, inStock: false },
  { name: 'Tablet', price: 500, inStock: true },
  { name: 'Monitor', price: 300, inStock: true }
];

// 재고가 있는 상품만
const availableProducts = products.filter(product => product.inStock);
console.log(availableProducts);
// [
//   { name: 'Laptop', price: 1200, inStock: true },
//   { name: 'Tablet', price: 500, inStock: true },
//   { name: 'Monitor', price: 300, inStock: true }
// ]

// 가격이 600 이하인 재고 상품
const affordableProducts = products.filter(product =>
  product.price <= 600 && product.inStock
);
console.log(affordableProducts);
// [
//   { name: 'Tablet', price: 500, inStock: true },
//   { name: 'Monitor', price: 300, inStock: true }
// ]

map + filter 체이닝

1
2
3
4
5
6
7
8
9
10
11
12
13
const users = [
  { name: 'Alice', age: 17 },
  { name: 'Bob', age: 25 },
  { name: 'Charlie', age: 16 },
  { name: 'David', age: 30 }
];

// 성인 사용자의 이름만 추출
const adultNames = users
  .filter(user => user.age >= 18)
  .map(user => user.name);

console.log(adultNames);  // ['Bob', 'David']

💡 메서드 체이닝: filter, map, reduce 등은 체이닝하여 강력한 데이터 처리 파이프라인을 만들 수 있습니다!

배열 검색 메서드

find() - 조건에 맞는 첫 번째 요소

find는 조건을 만족하는 첫 번째 요소를 반환합니다.

기본 문법

1
2
3
const element = array.find((element, index, array) => {
  return condition;
});

기본 예제

1
2
3
4
5
6
7
8
9
const numbers = [5, 12, 8, 130, 44];

// 10보다 큰 첫 번째 수
const found = numbers.find(num => num > 10);
console.log(found);  // 12

// 조건을 만족하는 요소가 없으면 undefined
const notFound = numbers.find(num => num > 200);
console.log(notFound);  // undefined

실전 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
const users = [
  { id: 1, name: 'Alice', email: 'alice@example.com' },
  { id: 2, name: 'Bob', email: 'bob@example.com' },
  { id: 3, name: 'Charlie', email: 'charlie@example.com' }
];

// ID로 사용자 찾기
const user = users.find(u => u.id === 2);
console.log(user);  // { id: 2, name: 'Bob', email: 'bob@example.com' }

// 이메일로 사용자 찾기
const userByEmail = users.find(u => u.email === 'alice@example.com');
console.log(userByEmail);  // { id: 1, name: 'Alice', ... }

findIndex() - 조건에 맞는 첫 번째 요소의 인덱스

1
2
3
4
5
6
7
8
const numbers = [5, 12, 8, 130, 44];

const index = numbers.findIndex(num => num > 10);
console.log(index);  // 1 (12의 인덱스)

// 못 찾으면 -1 반환
const notFoundIndex = numbers.findIndex(num => num > 200);
console.log(notFoundIndex);  // -1

find vs filter 비교

구분findfilter
반환값첫 번째 요소 (또는 undefined)모든 일치 요소의 배열
성능빠름 (찾으면 즉시 중단)느림 (전체 탐색)
용도하나의 요소 찾기여러 요소 필터링

배열 판별 메서드

some() - 하나라도 조건 만족?

some하나 이상의 요소가 조건을 만족하면 true를 반환합니다.

1
2
3
4
5
6
7
8
9
const numbers = [1, 2, 3, 4, 5];

// 짝수가 하나라도 있는가?
const hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven);  // true

// 10보다 큰 수가 있는가?
const hasGreaterThan10 = numbers.some(num => num > 10);
console.log(hasGreaterThan10);  // false

every() - 모두 조건 만족?

every모든 요소가 조건을 만족해야 true를 반환합니다.

1
2
3
4
5
6
7
8
9
const numbers = [2, 4, 6, 8, 10];

// 모두 짝수인가?
const allEven = numbers.every(num => num % 2 === 0);
console.log(allEven);  // true

// 모두 5보다 큰가?
const allGreaterThan5 = numbers.every(num => num > 5);
console.log(allGreaterThan5);  // false

실전 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
const users = [
  { name: 'Alice', age: 25, verified: true },
  { name: 'Bob', age: 30, verified: true },
  { name: 'Charlie', age: 17, verified: false }
];

// 한 명이라도 미성년자인가?
const hasMinor = users.some(user => user.age < 18);
console.log(hasMinor);  // true

// 모두 인증된 사용자인가?
const allVerified = users.every(user => user.verified);
console.log(allVerified);  // false

reduce() - 배열 축약하기

reduce는 배열의 모든 요소를 하나의 값으로 축약(reduce)합니다.

기본 문법

1
2
3
const result = array.reduce((accumulator, currentValue, index, array) => {
  return newAccumulator;
}, initialValue);

매개변수:

  • accumulator: 누적값
  • currentValue: 현재 처리 중인 요소
  • initialValue: 초기값 (선택, 권장)

기본 예제: 합계 구하기

1
2
3
4
5
6
7
8
9
10
11
12
const numbers = [1, 2, 3, 4, 5];

// 배열의 합
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum);  // 15

// 동작 과정:
// acc = 0, num = 1 → return 1
// acc = 1, num = 2 → return 3
// acc = 3, num = 3 → return 6
// acc = 6, num = 4 → return 10
// acc = 10, num = 5 → return 15

실전 예제

1. 장바구니 총액 계산

1
2
3
4
5
6
7
8
9
10
11
const cart = [
  { name: 'Laptop', price: 1200, quantity: 1 },
  { name: 'Phone', price: 800, quantity: 2 },
  { name: 'Tablet', price: 500, quantity: 1 }
];

const total = cart.reduce((sum, item) => {
  return sum + (item.price * item.quantity);
}, 0);

console.log(total);  // 3300

2. 배열을 객체로 변환

1
2
3
4
5
6
7
8
9
10
const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];

// 과일 개수 세기
const fruitCount = fruits.reduce((counts, fruit) => {
  counts[fruit] = (counts[fruit] || 0) + 1;
  return counts;
}, {});

console.log(fruitCount);
// { apple: 3, banana: 2, orange: 1 }

3. 중첩 배열 평탄화

1
2
3
4
5
6
7
const nestedArray = [[1, 2], [3, 4], [5, 6]];

const flattened = nestedArray.reduce((flat, arr) => {
  return flat.concat(arr);
}, []);

console.log(flattened);  // [1, 2, 3, 4, 5, 6]

4. 함수 합성 (고급)

1
2
3
4
5
6
7
8
9
const double = x => x * 2;
const square = x => x * x;
const addTen = x => x + 10;

const compose = (...fns) => x =>
  fns.reduceRight((acc, fn) => fn(acc), x);

const calculate = compose(addTen, square, double);
console.log(calculate(5));  // ((5 * 2) ^ 2) + 10 = 110

💡 reduce의 힘: 거의 모든 배열 연산을 reduce로 구현할 수 있습니다!

기타 유용한 배열 메서드

includes() - 요소 포함 여부

1
2
3
4
const fruits = ['apple', 'banana', 'orange'];

console.log(fruits.includes('banana'));  // true
console.log(fruits.includes('grape'));   // false

sort() - 배열 정렬

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const numbers = [3, 1, 4, 1, 5, 9, 2, 6];

// 오름차순
numbers.sort((a, b) => a - b);
console.log(numbers);  // [1, 1, 2, 3, 4, 5, 6, 9]

// 내림차순
numbers.sort((a, b) => b - a);
console.log(numbers);  // [9, 6, 5, 4, 3, 2, 1, 1]

// 객체 배열 정렬
const users = [
  { name: 'Charlie', age: 35 },
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 }
];

users.sort((a, b) => a.age - b.age);
// 나이순 정렬: Alice(25), Bob(30), Charlie(35)

⚠️ 주의: sort()원본 배열을 변경합니다!

slice() - 배열 일부 추출

1
2
3
4
5
const arr = [1, 2, 3, 4, 5];

const sliced = arr.slice(1, 4);  // 인덱스 1부터 3까지 (4 제외)
console.log(sliced);  // [2, 3, 4]
console.log(arr);     // [1, 2, 3, 4, 5] (원본 유지)

concat() - 배열 합치기

1
2
3
4
5
6
7
8
9
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

const combined = arr1.concat(arr2);
console.log(combined);  // [1, 2, 3, 4, 5, 6]

// Spread 연산자 사용 (모던한 방법)
const combined2 = [...arr1, ...arr2];
console.log(combined2);  // [1, 2, 3, 4, 5, 6]

join() - 배열을 문자열로

1
2
3
4
5
6
7
const words = ['Hello', 'World', '!'];

const sentence = words.join(' ');
console.log(sentence);  // 'Hello World !'

const csv = ['apple', 'banana', 'orange'].join(',');
console.log(csv);  // 'apple,banana,orange'

실전 종합 예제

데이터 처리 파이프라인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const transactions = [
  { id: 1, type: 'income', amount: 5000, date: '2024-01-15' },
  { id: 2, type: 'expense', amount: 2000, date: '2024-01-16' },
  { id: 3, type: 'income', amount: 3000, date: '2024-01-17' },
  { id: 4, type: 'expense', amount: 1500, date: '2024-01-18' },
  { id: 5, type: 'income', amount: 4000, date: '2024-01-19' }
];

// 1. 수입만 필터링
// 2. 금액에 10% 세금 적용
// 3. 총 세후 수입 계산
const totalNetIncome = transactions
  .filter(t => t.type === 'income')
  .map(t => t.amount * 0.9)
  .reduce((sum, amount) => sum + amount, 0);

console.log(totalNetIncome);  // 10800

// 한 줄로 작성 가능!
const result = transactions
  .filter(t => t.type === 'income')
  .reduce((sum, t) => sum + t.amount * 0.9, 0);

E-commerce 상품 필터링

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const products = [
  { id: 1, name: 'Laptop', price: 1200, category: 'Electronics', rating: 4.5 },
  { id: 2, name: 'Phone', price: 800, category: 'Electronics', rating: 4.7 },
  { id: 3, name: 'Shirt', price: 50, category: 'Clothing', rating: 4.2 },
  { id: 4, name: 'Tablet', price: 500, category: 'Electronics', rating: 4.6 },
  { id: 5, name: 'Jeans', price: 80, category: 'Clothing', rating: 4.0 }
];

// 전자제품 중 평점 4.5 이상인 제품의 이름
const topElectronics = products
  .filter(p => p.category === 'Electronics' && p.rating >= 4.5)
  .map(p => p.name);

console.log(topElectronics);  // ['Laptop', 'Phone', 'Tablet']

// 카테고리별 평균 가격
const avgPriceByCategory = products.reduce((acc, product) => {
  const cat = product.category;
  if (!acc[cat]) {
    acc[cat] = { sum: 0, count: 0 };
  }
  acc[cat].sum += product.price;
  acc[cat].count++;
  return acc;
}, {});

Object.keys(avgPriceByCategory).forEach(category => {
  const { sum, count } = avgPriceByCategory[category];
  console.log(`${category}: ${sum / count}`);
});
// Electronics: 833.33
// Clothing: 65

성능 고려사항

메서드 체이닝 vs 단일 루프

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// ❌ 비효율적: 배열을 3번 순회
const result1 = numbers
  .filter(n => n > 5)      // 1번째 순회
  .map(n => n * 2)         // 2번째 순회
  .reduce((sum, n) => sum + n, 0);  // 3번째 순회

// ✅ 효율적: 배열을 1번만 순회
const result2 = numbers.reduce((sum, n) => {
  if (n > 5) {
    sum += n * 2;
  }
  return sum;
}, 0);

💡 : 작은 배열(<1000개)은 가독성을 위해 체이닝, 큰 배열은 성능을 위해 단일 루프를 고려하세요!

핵심 정리

자주 사용하는 메서드 비교

메서드반환값원본 변경용도
forEachundefined각 요소 순회
map새 배열배열 변환
filter새 배열조건에 맞는 요소만
reduce단일 값배열 축약
find요소 또는 undefined첫 번째 요소 찾기
someboolean하나라도 만족?
everyboolean모두 만족?
sort정렬된 배열배열 정렬
slice새 배열배열 일부 추출

메서드 선택 가이드

1
2
3
4
5
6
7
8
무엇을 하고 싶은가?
├─ 각 요소 처리만? → forEach
├─ 새 배열로 변환? → map
├─ 조건에 맞는 요소만? → filter
├─ 하나의 값으로 축약? → reduce
├─ 특정 요소 찾기? → find/findIndex
├─ 조건 판별? → some/every
└─ 배열 일부만? → slice

Best Practices

  1. 불변성 유지: 원본 배열을 변경하지 않는 메서드 선호
  2. 체이닝 활용: 여러 메서드를 연결하여 파이프라인 구성
  3. 가독성 우선: 성능이 문제되지 않으면 가독성 있는 코드 작성
  4. 적절한 메서드 선택: 목적에 맞는 메서드 사용

배열 메서드를 마스터하면 더 간결하고 표현력 있는 코드를 작성할 수 있습니다!

참고 자료

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.