JavaScript-myArray.forEach 대 for 루프의 뉘앙스


88

사용을 제안하는 많은 질문을 보았습니다.

for (var i = 0; i < myArray.length; i++){ /* ... */ }

대신에:

for (var i in myArray){ /* ... */ }

일관되지 않은 반복으로 인해 배열의 경우 ( 여기 참조 ).


그러나 객체 지향 루프를 선호하는 것처럼 보이는 것을 찾을 수 없습니다.

myArray.forEach(function(item, index){ /* ... */ });

나에게 훨씬 더 직관적 인 것 같습니다.

현재 프로젝트의 경우 IE8 호환성이 중요하며 Mozilla의 polyfill 사용을 고려 하고 있지만 이것이 어떻게 작동하는지 100 % 확신하지는 않습니다.

  • 표준 for 루프 (위의 첫 번째 예)와 최신 브라우저의 Array.prototype.forEach 구현간에 차이점이 있습니까?
  • 최신 브라우저 구현과 위에 링크 된 Mozilla 구현 사이에 차이가 있습니까 (IE8과 관련하여)?
  • 성능은 문제가 아니라 속성이 반복되는 일관성에 불과합니다.

6
에서 break나갈 수 없습니다 forEach. 그러나 큰 장점은 기능으로 새로운 범위를 만드는 것입니다. polyfill을 사용하면 문제가 없어야합니다 (적어도 나는 전혀 발생하지 않았습니다).
hgoebl

나이가 IE와 함께있을 수있는 문제는 심 자체가 아니라 깨진 배열 생성자 / 문자 WRT holesundefined이어야하며, 다른 깨진 방법, 같은 slicehasOwnPropertyWRT는 DOM 객체를 arraylike 할 수 있습니다. 내 테스트 es5 shim는 사양을 준수하는 그러한 shimmed 방법을 보여주었습니다 (테스트 된 MDN의 shim이 아님).
Xotic750

1
그리고 for루프에서 벗어나는 것이 바로 그 이유 some입니다.
Xotic750

1
"그러나 나는 객체 지향 루프를 선호하는 것 같은 것을 찾을 수없는 것 같다."나는 그것을 기능적 방식과 명령 적 방식이라고 부르고 싶다.
Memke 2016

Array.find()첫 번째 일치 항목을 찾은 후 루프를 벗어나는 데 사용할 수 있습니다 .
Mottie

답변:


121

for루프와 forEach메서드 의 가장 큰 차이점 은 전자를 사용하면 break루프를 벗어날 수 있다는 것입니다. 에 continue전달 된 함수에서 간단히 반환하여 시뮬레이션 할 수 forEach있지만 루프를 완전히 중지 할 수있는 방법은 없습니다.

그 외에도 둘은 동일한 기능을 효과적으로 수행합니다. 또 다른 사소한 차이점은 변수 호이 스팅으로 인해 for 루프의 인덱스 범위 (및 모든 포함 변수)와 관련이 있습니다.

// 'i' is scoped to the containing function
for (var i = 0; i < arr.length; i++) { ... }

// 'i' is scoped to the internal function
arr.forEach(function (el, i) { ... });

그러나 forEach이것이 훨씬 더 표현 적이라는 것을 알게되었습니다 . 배열의 각 요소를 반복하려는 의도를 나타내며 인덱스뿐만 아니라 요소에 대한 참조를 제공합니다. 전반적으로 대부분 개인 취향에 따라 다르지만을 사용할 수 있다면 forEach사용하는 것이 좋습니다.


특히 성능과 관련하여 두 버전 간에는 몇 가지 실질적인 차이점이 있습니다. 사실, 간단한 for 루프 forEach이 jsperf 테스트에서 보여준 것처럼 메서드 보다 훨씬 더 나은 성능 을 발휘합니다 .

이러한 성능이 필요한지 여부는 사용자가 결정해야하며, 대부분의 경우 속도보다는 표현력을 선호합니다. 이 속도 차이는 이 답변 에서 언급했듯이 기본 루프와 희소 배열에서 작동하는 방법 간의 사소한 의미 차이 때문일 수 있습니다.

의 동작이 필요하지 않거나 forEach루프를 조기에 중단해야하는 경우 Lo-Dash를 _.each대안으로 사용할 수 있으며 이는 브라우저 간에서도 작동합니다. jQuery를 사용하는 경우 유사한을 제공합니다 $.each. 각 변형에서 콜백 함수에 전달되는 인수의 차이점에 유의하세요.

( forEach폴리 필의 경우 해당 경로를 선택하면 이전 브라우저에서 문제없이 작동합니다.)


1
라이브러리 버전 each은의 ECMA5 사양과 동일한 방식으로 작동하지 않으며 forEach모든 어레이를 조밀하게 취급하는 경향이 있습니다 (사용자가 알고있는 경우 IE 버그를 방지하기 위해). 그렇지 않으면 "gotcha"가 될 수 있습니다. 참고로 github.com/es-shims/es5-shim/issues/190
Xotic750

7
또한 Array.prototype.some진실 값을 반환 할 때까지 또는 배열을 완전히 반복 할 때까지 반복되는 것과 같이 중단 할 수있는 몇 가지 프로토 타입 메서드가 있습니다 . Array.prototype.every유사 Array.prototype.some하지만 거짓 값을 반환하면 중지됩니다.
axelduch 2014 년

다른 브라우저와 shim에서 일부 테스트 결과를보고 싶다면 여기 ci.testling.com/Xotic750/util-x
Xotic750

또한 Array.prototype.forEach를 사용하면 코드가 확장에 따라 달라집니다. 예를 들어 페이지에 포함 할 코드를 작성하는 경우 Array.prototype.forEach가 다른 것으로 덮어 쓸 가능성이 있습니다.
Marble Daemon

2
@MarbleDaemon 그 기회는 너무 적어서 사실상 불가능하므로 무시할 수 있습니다. Array.prototype.forEach호환되지 않는 버전으로 덮어 쓰면 너무 많은 라이브러리가 손상 될 가능성이 있으므로 이러한 이유로 피하는 것이 도움이되지 않습니다.
Alexis King

12

Array.forEach보다 훨씬 더 잘 수행되는 사용자 정의 foreach 함수를 사용할 수 있습니다.

이것을 코드에 한 번 추가해야합니다. 이렇게하면 배열에 새로운 기능이 추가됩니다.

function foreach(fn) {
    var arr = this;
    var len = arr.length;
    for(var i=0; i<len; ++i) {
        fn(arr[i], i);
    }
}

Object.defineProperty(Array.prototype, 'customForEach', {
    enumerable: false,
    value: foreach
});

그런 다음 Array.forEach와 같은 어디에서나 사용할 수 있습니다.

[1,2,3].customForEach(function(val, i){

});

유일한 차이점은 3 배 더 빠릅니다. https://jsperf.com/native-arr-foreach-vs-custom-foreach

업데이트 : 새 Chrome 버전에서 .forEach ()의 성능이 향상되었습니다. 그러나이 솔루션은 다른 브라우저에서 추가 성능을 제공 할 수 있습니다.

JSPerf


4

많은 개발자 (예 : Kyle Simpson)가 .forEach배열에 부작용이 있고 .map순수 기능에 대한 것을 나타내는 데 사용 하도록 제안했습니다 . for루프는 알려진 수의 루프 또는 대부분의 프로그래밍 언어에 대한 광범위한 지원으로 인해 통신하기가 더 쉽기 때문에 적합하지 않은 다른 경우에 대한 범용 솔루션으로 적합합니다.

예 :

/* For Loop known number of iterations */
const numberOfSeasons = 4;
for (let i = 0; i < numberOfSeasons; i++) {
  //Do Something
}

/* Pure transformation */
const arrayToBeUppercased = ['www', 'html', 'js', 'us'];
const acronyms = arrayToBeUppercased.map((el) => el.toUpperCase));

/* Impure, side-effects with .forEach */
const acronymsHolder = [];
['www', 'html', 'js', 'us'].forEach((el) => acronymsHolder.push(el.toUpperCase()));

관습 적으로는 이것이 가장 좋은 것 같지만 커뮤니티는 새로운 반복 프로토콜 for in루프 에 대한 관습에 실제로 정착하지 않았습니다 . 일반적으로 JS 커뮤니티에서 채택 할 수있는 FP 개념을 따르는 것이 좋습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.