[Javascript API] forEach() - 배열 메서드

Nayoung·2024년 11월 25일

Javascript API

목록 보기
2/7

1. 자바스크립트 배열 메서드 forEach()

forEach() 메서드는 자바스크립트의 배열 메서드로서, 제공하는 함수를 사용해 배열을 순회하며 각 요소에서 함수를 호출한다.
이 메서드는 모든 요소를 함수에 전달하기 전에 반복을 멈추는 방법이 없다. 즉, 일반적으로 for 루프에 사용하는 break 문과 같은 수단이 없다는 것이다.

forEach() 메서드는 반환값이 없다. 항상 undefined를 반환하며 배열을 순회하면서 작업을 수행하기때문에 주로 부수 효과(side effect)를 노리고 사용된다. 반환값이 필요한 작업에서는 map() 메서드를 대신 사용한다.

또한 콜백 함수 내부에서 배열을 변경하면 원본 배열에 영향을 미칠 수 있어 주의할 점이 꽤 많은 메서드이다.

하지만 배열을 순회하는 작업을 매우 간단하게 구현할 수 있게 해주는 메서드이기 때문에 자주 쓰인다.

1-1. forEach() 기본 문법

forEach() 메서드의 기본 문법은 다음과 같다.

array.forEach(callback(element, index, array), thisArg);

forEach()는 배열에 프로토타입 체인을 통해 접근한다.
위와 같이 forEach() 메서드는 요소를 돌며 호출할 콜백 함수를 첫 번째 인자로 받고, 두 번째 인자로는 콜백 함수에서 사용될 this를 정의하는 값을 받는다. 첫 번째 인자는 필수 사항이며 두 번째 인자는 선택 사항이다. 주로 첫 번째 인자만 사용된다.

또한 물론 두 번째 인자인 this 값을 정의하는 thisArg콜백 함수화살표 함수가 아닌 function 키워드로 정의되었을 때에만 유효하다.
왜냐하면 화살표 함수는 자신만의 this를 가지지 않으며, 바깥 스코프의 this를 상속받기 때문이다. 따라서 화살표 함수로 작성하고 thisArg를 전달하면 이 값은 무시된다.

콜백 함수는 다음과 같은 세 개의 인자를 순서대로 받을 수 있다.

element : 배열에서 처리 중인 현재 요소

index : 배열에서 처리 중인 현재 요소의 인덱스

array : forEach()를 호출한 원본 배열 참조

1-2. forEach() 작성 예시

for 문으로 작성된 로직을 forEach()를 사용하여 리팩토링 해보자.

const items = ["item1", "item2", "item3"];
const copyItems = [];

// 리팩토링 전 for문 사용
for (let i = 0; i < items.length; i++) {
  copyItems.push(items[i]);
}

// 리팩토링 후 forEach() 사용. 훨씬 간결해졌다.
items.forEach((item) => {
  copyItems.push(item);
});

1-3. 주의할 점

1-3-1. 반복을 멈추는 방법이 없다

for 문의 break 처럼 반복을 중단하는 방법은 없다.
콜백 함수 안에서 어떤 조건에 따라 return 으로 함수 호출 후 중간에 중단을 할 수는 있겠지만 반복 자체를 멈추는 break 기능은 없다.

1-3-2. forEach() 메서드는 반환값이 없다

map()과 달리 forEach()는 항상 undefined를 반환하므로 체이닝할 수 없다.

const numbers = [1, 2, 3];

// forEach를 체이닝하려는 잘못된 시도
const result = numbers
  .forEach(num => console.log(num)) // 반환값은 undefined
  .map(num => num * 2); // 따라서 에러 발생: undefined에 map 메서드가 없음

console.log(result);

1-3-3. forEach()의 콜백함수가 원본 배열에 영향을 미칠 수 있다

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

// forEach 메서드에서 배열을 변경하는 예
arr.forEach((value, index, array) => {
  if (value === 2) {
    array[index] = 99; // 현재 요소를 변경
  }
  if (value === 4) {
    array.push(5); // 배열에 새 요소 추가
  }
});

console.log(arr);
// 출력: [1, 99, 3, 4, 5]

이렇게 forEach()는 원본 배열을 직접 참조하므로 콜백 함수 내에서 원본 배열을 변경하는 로직이 있다면, 실제 원본 배열이 변경된다.

1-3-4. forEach()는 프로미스를 기다리지 않는다

forEach() 메서드는 동기 함수를 기대하며 프로미스를 기다리지 않는다.

const ratings = [5, 4, 5];
let sum = 0;

const sumFunction = async (a, b) => a + b;

ratings.forEach(async (rating) => {
  sum = await sumFunction(sum, rating);
});

console.log(sum);
// 순진하게 예상한 출력: 14
// 실제 출력: 0

따라서 비동기 함수를 사용해야하는 경우, forEach() 대신 비동기 작업을 지원하는 for...of 문법이나 reduce() 메서드를 대신 사용해야한다.


글 작성 참고 사이트: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

profile
문제의 근본적인 원인을 탐구하고 해결하는 것을 좋아하는 프론트엔드 개발자, 진나영입니다!

0개의 댓글