forEach() 메서드는 주어진 함수를 배열 요소 각각에 대해 실행합니다.
The source for this interactive example is stored in a GitHub repository. If you'd like to contribute to the interactive examples project, please clone https://github.com/mdn/interactive-examples and send us a pull request.
구문
arr.forEach(callback[, thisArg]);
매개변수
callback- 각 요소에 대해 실행할 함수. 다음 세 가지 인수를 받습니다.
-
currentValue- 처리할 현재 요소.
indexOptional- 처리할 현재 요소의 인덱스.
arrayOptional- forEach()를 호출한 배열.
thisArgOptionalcallback을 실행할 때this로 사용할 값.
반환 값
설명
forEach()는 주어진 callback을 배열에 있는 각 요소에 대해 오름차순으로 한 번씩 실행합니다. 삭제했거나 초기화하지 않은 인덱스 속성에 대해서는 실행하지 않습니다. (예: 희소 배열)
callback은 다음 세 인수와 함께 호출됩니다.
- 요소 값
- 요소 인덱스
- 순회 중인 배열
thisArg 매개변수를 forEach()에 제공한 경우 callback을 호출할 때 전달해 this의 값으로 쓰입니다. 전달하지 않으면 undefined를 사용하며, 최종 this 값은 함수의 this를 결정하는 평소 규칙을 따릅니다.
forEach()로 처리할 요소의 범위는 최초 callback 호출 전에 설정됩니다. forEach() 호출을 시작한 뒤 배열에 추가한 요소는 callback이 방문하지 않습니다. 배열의 기존 요소값이 바뀐 경우, callback에 전달하는 값은 forEach()가 요소를 방문한 시점의 값을 사용합니다. 방문하기 전에 삭제한 요소는 방문하지 않습니다.
forEach()는 각 배열 요소에 대해 한 번씩 callback 함수를 실행합니다. map()과 reduce()와는 달리 undefined를 반환하기 때문에 메서드 체인의 중간에 사용할 수 없습니다. 대표적인 사용처는 메서드 체인 끝에서 부작용side effect을 실행하는 겁니다.
forEach()는 배열을 변형하지 않습니다. 그러나 callback이 변형할 수는 있습니다.
예외를 던지지 않고는 forEach()를 중간에 멈출 수 없습니다. 중간에 멈춰야 한다면 forEach()가 적절한 방법이 아닐지도 모릅니다.
다음 방법으로는 조기에 반복을 종료할 수 있습니다.
- 간단한 반복문
- for...of 반복문
Array.prototype.every()Array.prototype.some()Array.prototype.find()Array.prototype.findIndex()
다른 배열 메서드, every(), some(), find(), findIndex()는 배열 요소를 판별 함수에 전달하고, 그 결과의 참/거짓 여부에 따라 반복의 종료 여부를 결정합니다.
예제
for 반복문을 forEach로 바꾸기
const items = ['item1', 'item2', 'item3'];
const copy = [];
// 이전
for (let i=0; i<items.length; i++) {
copy.push(items[i]);
}
// 이후
items.forEach(function(item){
copy.push(item);
});
배열 콘텐츠 출력
참고: console.table()을 사용하면 배열 내용물을 서식에 맞춰 출력할 수 있습니다. 다음 예제는 forEach()를 사용한 다른 방법을 소개합니다.
다음 코드는 배열의 각 요소에 대해 한 줄을 기록합니다:
function logArrayElements(element, index, array) {
console.log('a[' + index + '] = ' + element);
}
// 인덱스 2는 배열의 그 위치에 항목이 없기에
// 건너뜀을 주의하세요.
[2, 5, , 9].forEach(logArrayElements);
// 기록:
// a[0] = 2
// a[1] = 5
// a[3] = 9
thisArg 사용
다음 (지어낸) 예는 배열의 각 항목에서 객체의 속성을 갱신합니다:
function Counter() {
this.sum = 0;
this.count = 0;
}
Counter.prototype.add = function(array) {
array.forEach(function(entry) {
this.sum += entry;
++this.count;
}, this);
// ^---- 주의
};
var obj = new Counter();
obj.add([2, 5, 9]);
obj.count
// 3
obj.sum
// 16
thisArg 매개변수(this)를 forEach()에 제공했기에, callback은 전달받은 this의 값을 자신의 this 값으로 사용할 수 있습니다.
객체 복사 함수
다음 코드는 주어진 객체의 사본을 만듭니다. 객체 사본을 만드는 여러 방법이 있습니다, 다음은 그저 한 방법으로 ECMAScript 5 Object.* 메타 속성 함수를 사용하여 Array.prototype.forEach()가 작동하는 법을 설명하기 위해 제시되었습니다.
function copy(obj) {
var copy = Object.create(Object.getPrototypeOf(obj));
var propNames = Object.getOwnPropertyNames(obj);
propNames.forEach(function(name) {
var desc = Object.getOwnPropertyDescriptor(obj, name);
Object.defineProperty(copy, name, desc);
});
return copy;
}
var obj1 = { a: 1, b: 2 };
var obj2 = copy(obj1); // obj2는 이제 obj1처럼 보임
반복 중에 배열이 변경되면 다른 요소들을 건너 뛸 수도 있습니다.
다음 예제에서는 "one", "two", "four"를 기록합니다. 값 "two"를 포함하는 항목에 도달하면 전체 배열의 첫 번째 항목이 제거되어 나머지 항목이 한 위치 앞으로 이동합니다. 요소 "four"는 이제 배열의 앞쪽 위치에 있으므로 "three"는 건너 뜁니다. forEach()는 반복하기 전에 배열 복사본을 만들지 않습니다.
var words = ['one', 'two', 'three', 'four'];
words.forEach(function(word) {
console.log(word);
if (word === 'two') {
words.shift();
}
});
// one
// two
// four
폴리필
forEach는 ECMA-262 표준 제5판에 추가됐으므로 어떤 표준 구현체에서는 사용하지 못할 수도 있습니다. 다른 모든 코드 이전에 아래 코드를 포함하면 forEach를 지원하지 않는 환경에서도 사용할 수 있습니다. 아래 알고리즘은 Object와 TypeError가 변형되지 않고, callback.call()의 평가 값이 원래의 Function.prototype.call()과 같은 경우 ECMA-262 제5판이 명시한 것과 동일합니다.
// ECMA-262 5판, 15.4.4.18항의 작성 과정
// 참고: http://es5.github.io/#x15.4.4.18
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(callback, thisArg) {
var T, k;
if (this === null) {
throw new TypeError(' this is null or not defined');
}
// 1. O를 인수로서 |this| 값을 전달한
// toObject() 호출의 결과이게 함.
var O = Object(this);
// 2. lenValue를 "length" 인수가 있는 O의 Get()
// 내부 메소드 호출의 결과이게 함.
// 3. len을 toUint32(lenValue)이게 함.
var len = O.length >>> 0;
// 4. isCallable(callback)이 false인 경우, TypeError 예외 발생.
// 참조: http://es5.github.com/#x9.11
if (typeof callback !== "function") {
throw new TypeError(callback + ' is not a function');
}
// 5. thisArg가 공급됐다면, T를 thisArg이게 함;
// 아니면 T를 undefined이게 함.
if (arguments.length > 1) {
T = thisArg;
}
// 6. k를 0이게 함
k = 0;
// 7. 반복, k < len일 동안
while (k < len) {
var kValue;
// a. Pk를 ToString(k)이게 함.
// 이는 in 연산자의 좌변(LHS) 피연산자에 대한 묵시(implicit)임
// b. kPresent를 Pk 인수가 있는 O의 HasProperty
// 내부 메소드 호출의 결과이게 함.
// 이 과정은 c와 결합될 수 있음
// c. kPresent가 true인 경우, 그러면
if (k in O) {
// i. kValue를 인수 Pk가 있는 O의 Get 내부
// 메소드 호출의 결과이게 함.
kValue = O[k];
// ii. this 값으로 T 그리고 kValue, k 및 O을 포함하는
// 인수 목록과 함께 callback의 call 내부 메소드 호출.
callback.call(T, kValue, k, O);
}
// d. k를 1씩 증가.
k++;
}
// 8. undefined 반환
};
}
명세
브라우저 호환성
| Desktop | Mobile | Server | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
forEach | Chrome Full support Yes | Edge Full support 12 | Firefox Full support 1.5 | IE Full support 9 | Opera Full support Yes | Safari Full support Yes | WebView Android Full support Yes | Chrome Android Full support Yes | Firefox Android Full support 4 | Opera Android Full support Yes | Safari iOS Full support Yes | Samsung Internet Android Full support Yes | nodejs Full support Yes |
Legend
- Full support
- Full support