모든 강의를 무료로 볼 수 있어요. 회원가입 없이도 학습 가능합니다.

12강 / 전체 22강

배열 메서드 ①

13분 읽기 조회 10

forEach·map·filter·find·findIndex를 화살표 함수와 결합해 배열 데이터를 선언적으로 처리하는 현대적인 방법을 실전 예제로 완전히 익힙니다.

🎯 학습 목표

이 강을 마치면 다음을 할 수 있습니다.

  • forEach로 배열의 각 요소에 부작용(side effect)을 일으키는 작업을 수행할 수 있습니다.
  • map으로 배열의 모든 요소를 변환한 새 배열을 만들 수 있습니다.
  • filter로 조건에 맞는 요소만 골라낸 새 배열을 만들 수 있습니다.
  • find와 findIndex로 조건을 만족하는 요소를 검색할 수 있습니다.

💡 고차 배열 메서드란 무엇인가

이 섹션에서는 고차 배열 메서드의 개념과 전통적인 반복문 대비 장점을 살펴보겠습니다.

8강에서 for문으로 배열을 순회했습니다. 11강에서 for...of도 배웠습니다. 그런데 현대 자바스크립트 개발에서는 배열을 처리할 때 이보다 훨씬 더 강력하고 표현적인 도구를 사용합니다. 바로 고차 배열 메서드(Higher-Order Array Methods)입니다.

고차 배열 메서드는 배열에 내장된 메서드 중에서 함수(콜백)를 인수로 받는 것들입니다. 10강에서 배운 고차 함수와 콜백 함수 개념이 여기서 본격적으로 활용됩니다. 이 메서드들은 반복문으로 할 수 있는 것을 훨씬 짧고 의도가 명확한 코드로 표현하게 해줍니다.

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

// 전통적인 for문 — 명령형(어떻게)
const doubled = [];
for (let i = 0; i < numbers.length; i++) {
  doubled.push(numbers[i] * 2);
}
console.log(doubled);  // [2, 4, 6, 8, 10]

// map 메서드 — 선언형(무엇을)
const doubled2 = numbers.map(n => n * 2);
console.log(doubled2);  // [2, 4, 6, 8, 10]

두 코드는 같은 결과를 냅니다. 그러나 map을 사용한 코드는 "각 숫자를 2배로 만든 새 배열"이라는 의도가 코드 자체에서 드러납니다. 반면 for문은 어떻게 처리할지 절차를 하나씩 서술합니다. 이처럼 무엇을 할지에 집중하는 방식을 선언형(Declarative) 프로그래밍이라 하고, 어떻게 할지를 서술하는 방식을 명령형(Imperative) 프로그래밍이라 합니다. 현대 자바스크립트는 선언형 스타일을 강하게 지향합니다.

🔁 forEach — 각 요소에 작업 수행

이 섹션에서는 배열의 각 요소를 순회하며 부작용을 일으키는 forEach를 살펴보겠습니다.

forEach(callback)는 배열의 각 요소에 대해 콜백 함수를 한 번씩 실행합니다. 8강의 for문과 같은 역할이지만, 반환값이 없습니다(undefined를 반환). 따라서 결과를 변수에 담아 쓰는 것이 아니라, 콘솔 출력, DOM 수정, 데이터 전송처럼 부작용(Side Effect)을 일으킬 때 사용합니다.

const fruits = ["사과", "바나나", "포도", "딸기"];

// 기본 사용
fruits.forEach(fruit => {
  console.log(fruit);
});
// 사과, 바나나, 포도, 딸기

// 콜백의 두 번째 인수로 인덱스 접근
fruits.forEach((fruit, index) => {
  console.log(`${index + 1}. ${fruit}`);
});
// 1. 사과, 2. 바나나, 3. 포도, 4. 딸기

// 세 번째 인수로 원본 배열 접근
fruits.forEach((fruit, index, array) => {
  console.log(`${fruit} (전체 ${array.length}개 중 ${index + 1}번째)`);
});

// 실전 활용: 장바구니 합계 계산
const cart = [
  { name: "노트북", price: 1200000 },
  { name: "마우스", price: 35000 },
  { name: "키보드", price: 85000 }
];
let total = 0;
cart.forEach(item => {
  total += item.price;
});
console.log(`합계: ${total.toLocaleString()}원`);  // 합계: 1,320,000원

forEach의 콜백은 최대 세 개의 인수를 받을 수 있습니다: 요소(element), 인덱스(index), 원본 배열(array). 모두 필요하지 않으면 필요한 것만 선언하면 됩니다. forEach는 반환값이 없으므로, 새 배열을 만들거나 검색에는 사용하지 않습니다. 그런 목적에는 각각 map과 find를 사용합니다.

🗺️ map — 배열 변환

이 섹션에서는 배열의 모든 요소를 변환하여 같은 길이의 새 배열을 만드는 map을 살펴보겠습니다.

map(callback)은 배열의 각 요소에 콜백을 적용하고, 그 반환값들로 이루어진 새 배열을 반환합니다. 원본 배열은 변경되지 않습니다. 배열의 모든 요소를 어떤 방식으로든 변환할 때 가장 많이 사용하는 메서드입니다.

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

// 각 숫자를 제곱
const squared = numbers.map(n => n ** 2);
console.log(squared);   // [1, 4, 9, 16, 25]
console.log(numbers);   // [1, 2, 3, 4, 5] — 원본 변경 없음!

// 숫자를 문자열로 변환
const strings = numbers.map(n => `${n}번`);
console.log(strings);   // ["1번", "2번", "3번", "4번", "5번"]

// 객체 배열 변환 — 실무에서 가장 자주 사용!
const users = [
  { id: 1, firstName: "길동", lastName: "홍", age: 28 },
  { id: 2, firstName: "철수", lastName: "김", age: 24 },
  { id: 3, firstName: "영희", lastName: "이", age: 31 }
];

// 이름만 추출한 배열
const names = users.map(user => `${user.lastName}${user.firstName}`);
console.log(names);  // ["홍길동", "김철수", "이영희"]

// 특정 속성만 뽑아 새 객체 배열 생성
const summary = users.map(user => ({
  id: user.id,
  fullName: `${user.lastName}${user.firstName}`
}));
console.log(summary);
// [{ id: 1, fullName: "홍길동" }, { id: 2, fullName: "김철수" }, ...]

map은 항상 원본과 같은 길이의 새 배열을 반환합니다. 이것이 다음에 배울 filter와의 핵심 차이입니다. 실무에서는 서버 API에서 받은 복잡한 데이터 구조를 화면에 표시하기 좋은 형태로 변환할 때 map을 가장 많이 사용합니다. 예를 들어 상품 목록 데이터를 카드 컴포넌트에 맞는 형태로 재구성하거나, 숫자 데이터에 단위를 붙이는 등의 작업이 대표적입니다.

🔎 filter — 조건에 맞는 요소만 선택

이 섹션에서는 배열에서 조건을 만족하는 요소만 골라내어 새 배열을 만드는 filter를 살펴보겠습니다.

filter(callback)는 콜백이 true를 반환하는 요소만 포함한 새 배열을 반환합니다. 원본 배열은 변경되지 않습니다. 결과 배열의 길이는 원본보다 작거나 같습니다.

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

// 짝수만 걸러내기
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens);  // [2, 4, 6, 8, 10]

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

// 실전: 재고 있는 상품만
const products = [
  { name: "노트북", price: 1200000, inStock: true },
  { name: "마우스", price: 35000,   inStock: false },
  { name: "키보드", price: 85000,   inStock: true },
  { name: "모니터", price: 450000,  inStock: false },
  { name: "웹캠",   price: 75000,   inStock: true }
];

const available = products.filter(p => p.inStock);
console.log(available.map(p => p.name));
// ["노트북", "키보드", "웹캠"]

// 가격 범위 필터 (50,000원 이상 200,000원 이하)
const midRange = products.filter(p => p.price >= 50000 && p.price <= 200000);
console.log(midRange.map(p => p.name));
// ["키보드", "웹캠"]

// 문자열 검색 필터
const keyword = "마";
const searchResult = products.filter(p =>
  p.name.includes(keyword)
);
console.log(searchResult.map(p => p.name));  // ["마우스"]

filter의 콜백은 각 요소를 받아 true 또는 false(또는 Truthy/Falsy 값)를 반환해야 합니다. true를 반환하면 해당 요소가 결과 배열에 포함되고, false이면 제외됩니다. 검색 기능, 카테고리 필터링, 조건부 목록 표시 등 실무에서 매우 광범위하게 사용됩니다.

filter와 map을 연결하면(메서드 체이닝) 강력한 데이터 파이프라인을 만들 수 있습니다.

// 메서드 체이닝: filter 후 map
const result = products
  .filter(p => p.inStock)           // 재고 있는 것만
  .filter(p => p.price < 200000)   // 20만원 미만만
  .map(p => `${p.name}: ${p.price.toLocaleString()}원`);  // 문자열로 변환

console.log(result);
// ["마우스: 35,000원", ... ]  ← 마우스는 inStock false라 빠짐
// ["키보드: 85,000원", "웹캠: 75,000원"]

🔍 find와 findIndex — 조건에 맞는 요소 찾기

이 섹션에서는 배열에서 조건을 만족하는 첫 번째 요소 또는 그 인덱스를 찾는 find와 findIndex를 살펴보겠습니다.

find(callback)은 콜백이 true를 반환하는 첫 번째 요소를 반환합니다. 없으면 undefined를 반환합니다. findIndex(callback)는 같은 방식으로 첫 번째 일치 요소의 인덱스를 반환합니다. 없으면 -1을 반환합니다.

const users = [
  { id: 1, name: "홍길동", role: "admin" },
  { id: 2, name: "김철수", role: "user" },
  { id: 3, name: "이영희", role: "user" },
  { id: 4, name: "박민준", role: "admin" }
];

// id로 특정 사용자 찾기
const user = users.find(u => u.id === 3);
console.log(user);  // { id: 3, name: "이영희", role: "user" }

// 없으면 undefined
const notFound = users.find(u => u.id === 99);
console.log(notFound);  // undefined

// findIndex — 인덱스가 필요할 때
const idx = users.findIndex(u => u.name === "김철수");
console.log(idx);  // 1

// 실전: 찾은 후 수정 (splice와 조합)
const itemIdx = users.findIndex(u => u.id === 2);
if (itemIdx !== -1) {
  users[itemIdx] = { ...users[itemIdx], role: "moderator" };  // 불변 업데이트
}
console.log(users[1].role);  // "moderator"

filter와 find의 차이가 중요합니다. filter는 조건에 맞는 모든 요소의 배열을 반환하고, find는 조건에 맞는 첫 번째 요소 하나만 반환합니다. ID로 특정 항목 하나를 찾을 때는 find가 더 적합합니다. 또한 find는 조건을 만족하는 요소를 발견하면 즉시 검색을 멈추므로 filter보다 빠릅니다.

⚠️ 자주 하는 실수와 주의점

이 섹션에서는 고차 배열 메서드 사용 시 입문자들이 자주 겪는 실수를 살펴보겠습니다.

map에서 반환값을 빠뜨리는 실수가 매우 흔합니다. map의 콜백에서 return을 빠뜨리면 모든 요소가 undefined가 됩니다. 한 줄 축약 표기에서는 자동으로 반환되지만, 중괄호를 사용했다면 반드시 return을 명시해야 합니다.

const nums = [1, 2, 3];

// ❌ return 빠뜨림
const wrong = nums.map(n => {
  n * 2;  // return 없음!
});
console.log(wrong);  // [undefined, undefined, undefined]

// ✅ return 명시
const correct = nums.map(n => {
  return n * 2;
});
console.log(correct);  // [2, 4, 6]

// ✅ 한 줄 축약 (return 불필요)
const correct2 = nums.map(n => n * 2);
console.log(correct2);  // [2, 4, 6]

원본 배열이 바뀌지 않는다는 것을 잊는 실수도 주의해야 합니다. map과 filter는 새 배열을 반환하고 원본은 건드리지 않습니다. 결과를 변수에 저장해야 합니다. forEach는 반환값이 없으므로 결과를 변수에 담으면 undefined가 됩니다.

메서드 체이닝 순서도 중요합니다. filter 후 map과 map 후 filter는 결과는 같을 수 있지만 성능이 다릅니다. 먼저 filter로 개수를 줄이면 map이 처리할 요소가 적어 효율적입니다.

📝 핵심 요약

12강에서 배운 내용을 정리해 보겠습니다.

메서드반환값용도언제 사용
forEachundefined각 요소에 작업 수행콘솔 출력, DOM 수정 등 부작용
map새 배열 (같은 길이)모든 요소 변환데이터 형태 변환, 속성 추출
filter새 배열 (≤ 원본 길이)조건 만족 요소만 선택검색, 범위 필터링, 조건부 목록
find요소 하나 or undefined첫 번째 일치 요소ID로 항목 찾기
findIndex인덱스 or -1첫 번째 일치 인덱스위치 확인 후 수정·삭제

다음 강인 13강 — 배열 메서드 ②에서는 배열의 합계·최댓값을 구하는 reduce, 정렬하는 sort, 조건 검사를 하는 some·every를 배웁니다. 이 메서드들까지 익히면 어떤 복잡한 데이터 처리도 몇 줄로 해결할 수 있는 수준이 됩니다!

관련 주제

  • forEach
  • map
  • filter
  • find findIndex
  • 고차 배열 메서드
  • 개발·프로그래밍
  • 개발·프로그래밍 강의
  • 자바스크립트 기초 30강 — 웹을 움직이는 언어
  • 무료강의
  • 무료 온라인 강의
  • NUGUNA
  • 누구나

📚 시리즈 전체 공유

자바스크립트 기초 30강 — 웹을 움직이는 언어

이 강의가 속한 시리즈는 총 22강, 모두 무료입니다. 처음부터 배우려는 동료에게 시리즈 전체를 알려 주세요.

댓글

0/1000

불러오는 중...