상식에 사로잡히지 않는 JavaScript

[JavaScript] forEach의 순회를 멈추는 방법

노새두마리 2024. 3. 12. 17:08

forEach

forEach 메서드는 Array, Set, Map 자료형이 가지는 요소 순회 메서드입니다. 모든 요소에 대하여 주어진 콜백 함수를 호출하게 되며, forEach 자체적으로 순회를 종료시킬 수 있는 방법은 없습니다.

그럼에도 불구하고 순회를 종료하고 싶다면 대안은 있습니다.

1. 말 그대로 forEach 순회 자체를 종료시키는 방법입니다.

  • 특정 조건을 만족했을 때, 에러를 throw하도록 콜백 함수 설계
  • try - catch 문 사용

2. 순회 자체를 종료할 수는 없으나 추가 작업의 실행을 제한하는 방법입니다.

  • 특정 조건을 만족했을 때, 작업을 수행하지 않고 return하도록 콜백 함수 설계

1. 멈출 수 없다면 부숴버리겠어(try - catch)

프로그램 동작 중 오류를 throw하면 프로그램 자체가 종료된다는 점을 이용하는 방법입니다. 콜백 함수 내에서 throw를 활용하고 에러를 핸들링하는 문법을 적용하여 프로그램이 종료되는 것을 방지합니다.

try {
    let sum = 0;
    [1, 2, 3, 4].forEach(el => {
        console.log('visited: ', el);
        if (sum >= 3){
            throw new Error('satisfied break condition');
        }
        sum += el;
        console.log('sum: ', sum);
    });
} catch(e) {
    console.log(e);
}

// visited: 1
// sum: 1
// visited: 2
// sum: 3
// Error: satisfied break condition ...

개인적으로 오류가 아닌 것을 오류로 취급한다는 점, 로직의 전후로 try - catch 문이 추가된다는 점이 코드 스타일을 크게 해칩니다. 다음의 두 조건을 모두 만족하고 싶은 경우에 사용할 수 있습니다.

  • forEach 메서드를 반드시 사용해야겠다.
  • 조건을 만족하는 즉시 추가적인 함수 호출이 이루어지지 않도록 해야겠다.

실제 사용 예시

 

2174번: 로봇 시뮬레이션

첫째 줄에 두 정수 A, B가 주어진다. 다음 줄에는 두 정수 N, M이 주어진다. 다음 N개의 줄에는 각 로봇의 초기 위치(x, y좌표 순) 및 방향이 주어진다. 다음 M개의 줄에는 각 명령이 명령을 내리는 순

www.acmicpc.net

주어진 시뮬레이션이 유효한 시뮬레이션인지 묻는 문제로써, 중간에 실패하게 되면 오류로 간주하여 forEach문을 강제로 종료시킵니다. (line 38 ~ line 67)

 

공유 소스 보기

const readFile = () => require('fs').readFileSync('/dev/stdin').toString().trim(); const direction = { W: 0, N: 1, E: 2, S: 3, } const turnLeft = (cur, n = 1) => { return (cur + 4 * n - 1 * n) % 4; } const turnRight = (cur, n = 1) => { return (cur + 1 * n)

www.acmicpc.net

 


2. 내부 로직만 실행되지 않도록 하는 방법

반복을 완전히 멈추는 것이 아닌 콜백 함수의 로직 실행만을 막는 방법입니다. 특정 조건을 만족하는 경우 return하여 콜백 함수의 로직이 실행되지 않도록 합니다.

하지만 배열의 요소 전체에 대해 콜백 함수를 실행하는 동작을 유지합니다.

let sum = 0;
[1, 2, 3, 4].forEach(el => {
	console.log('visited: ', el);
	if (sum >= 3){
		return;
	}
	sum += el;
	console.log('sum: ', sum);
});
// visited: 1
// sum: 1
// visited: 2
// sum: 3
// visited: 3
// visited: 4

forEach 메서드가 가지는 코드 스타일을 유지하면서 함수의 반복 호출로 인한 부담을 최소화할 수 있는 방법입니다. 콜백 함수의 로직이 주어진 예시보다 훨씬 복잡한 경우, 무시 가능한 수준의 부담일 수 있습니다.


정리

오늘은 우아한 forEach 메서드를 야만적으로(!!) 종료시키는 방법에 대해 알아보았습니다.

개인적으로 원래 목적에 벗어난 문법을 적용하는 tricky한 방법들을 사용하기 보다 추가적인 순회가 유의미한 낭비를 일으키는지를 고려하여 상황에 맞게 forEach 메서드를 그대로 사용하거나 for 문을 사용하는 게 좋을 것 같습니다.

 

'24. 03. 13. - for 문의 break, Array.prototype.some 또는 Array.prototype.every를 활용한 트릭 관련 부분을 제거하였습니다. forEach를 사용하지 않는 시점에 이미 forEach를 중단하는 방법이 아니게 됩니다.

'24. 03. 16. try - catch 사용 예시 추가

https://stackoverflow.com/questions/6260756/how-to-stop-javascript-foreach