~에 대한 JavaScript


461

for ... in과 for 루프에 큰 차이가 있다고 생각하십니까? 어떤 종류의 "사용"을 선호하고 그 이유는 무엇입니까?

연관 배열의 배열이 있다고 가정 해 봅시다.

var myArray = [{'key': 'value'}, {'key': 'value1'}];

따라서 반복 할 수 있습니다.

for (var i = 0; i < myArray.length; i++)

과:

for (var i in myArray)

큰 차이는 보이지 않습니다. 성능 문제가 있습니까?


13
참고 우리는 또한 것을 JS 1.6로 ,이 있습니다 myArray.forEach(callback[, thisarg]).
Benji XVI

14
@ Benji array.forEach는 실제로 ES5에 있습니다.
mikemaccana

2
for-in 루프에서는 다음과 같은 조건이 필요합니다.if(myArray.hasOwnProperty(i)){true}
Eric Hodonsky

6
['foo', 'bar', 'baz'].forEach(function(element, index, array){ console.log(element, index, array); }); IE8을 제외하고는 거의 모든 곳에서 사용하는 것이 좋습니다 – 그것은 가장 우아한 구문입니다
Jon z

5
또한이 for...of문에 ECMAScript를 6 예를 들어, :for (let i of myArray) console.log(i);
Vitalii Fedorenko

답변:


548

선택은 관용구가 가장 잘 이해되는 것을 기반으로해야합니다.

배열은 다음을 사용하여 반복됩니다.

for (var i = 0; i < a.length; i++)
   //do stuff with a[i]

연관 배열로 사용되는 객체는 다음을 사용하여 반복됩니다.

for (var key in o)
  //do stuff with o[key]

지구가 산산이 부서지지 않는 한, 정해진 사용 패턴을 고수하십시오.


38
if 문 필터링과 함께 사용하는 것이 좋습니다. 반복자에 의해 리턴 된 멤버가 실제로 오브젝트의 멤버인지 확인하는 편리한 오브젝트 "obj.hasOwnProperty (member)"메소드가 있습니다. 참조 : javascript.crockford.com/code.html
Damir Zekić

57
다른 답변에서 언급했듯이 "for ... in"은 모든 Array 속성 및 메서드를 반복하므로 Array에 대해 올바르게 작동하지 않습니다. 따라서 객체 속성을 반복 할 때만 "for ... in"을 사용해야합니다. 그렇지 않으면 "for (i = 0; i <something; i ++)"
Denilson Sá Maia

성능상의 이유로 IMO for는 루프에서 매번 a.length를 평가하지 않고. 전에 배열의 길이를 평가하는 것이 좋습니다 .
UpTheCreek

9
@UpTheCreek : 배열이 실제로 HTMLDOM에 의해 반환 된 것이라면 사실이지만, 상당한 차이가 있기 전에 표준 자바 스크립트 배열이 얼마나 큰지 궁금합니다. 개인적으로 나는 뭔가 다른 것을 할 필요가있을 때까지 코드를 가능한 한 단순하게 유지하려고합니다.
AnthonyWJones

2
@Pichan 나는 당신이 for-loop 조건이 i < l아니라고 생각합니다 i < a.
맥스 나나시

161

Douglas Crockford 는 명령문 사용을 피하기 위해 JavaScript : Good Part (24 페이지)에서 권장 for in합니다.

for in객체에서 속성 이름을 반복 하는 데 사용 하면 결과가 정렬되지 않습니다. 최악의 결과 : 예기치 않은 결과가 발생할 수 있습니다. 여기에는 프로토 타입 체인에서 상속 된 멤버 및 메소드 이름이 포함됩니다.

속성을 제외한 모든 것을로 필터링 할 수 있습니다 .hasOwnProperty. 이 코드 샘플은 원래 원하는 것을 수행합니다.

for (var name in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, name)) {
        // DO STUFF
    }
}

70
for ... in은 객체 속성을 반복하는 데 완벽하게 적합합니다. 배열 요소를 반복하는 데는 적합하지 않습니다. 이 시나리오들 사이의 차이점을 이해할 수 없다면 그렇습니다. 그렇지 않으면 견딜 수 없습니다.
Shog9

8
주문이 아님을 강조하고 싶습니다! 이것은 큰 문제 일 수 있으며 잡기 어려운 버그 일 것입니다.
Jason

4
"프로토 타입 체인에서 상속 된 멤버 및 메소드 이름 포함"+1 예를 들어 누군가가 프로토 타입이로드 된 상태에서 코드를 사용하면 (코드가 실제로 사용하지 않더라도) 재미있게 사용할 수 있습니다.
ijw

13
변수 를 선언 하는 것을 잊지 마십시오 name. for(var name in object)...그렇지 않으면, 예를 들어 해당 코드가 함수 내에 있으면 name변수는 전역 객체의 속성이됩니다 ( 신고되지 않은 식별자에 대한 할당 은 새 ECMAScript에서도). 5 엄격 모드에서 해당 코드는 ReferenceError.
CMS

6
@Nosredna : John Resig 이외의 다른 사람이 제출 한 Chrome의 반복 순서에 대해서는 WontFix로 표시되는 문제가 있습니다. code.google.com/p/chromium/issues/detail?id=883 . 크롬 이전에도 속성을 제거한 다음 다시 추가하면 브라우저의 반복 순서가 동일하지 않았습니다. 또한 IE 9는 크롬과 비슷하게 동작합니다 (속도 향상을 위해). 따라서 ... 부정확 한 정보의 전파를 중단하십시오. 정보에 따라 보관하는 것이 매우 순진합니다.
Juan Mendes

62

참고-jQuery 사용자


jQuery의 each(callback)메소드는 for( ; ; )기본적으로 루프를 사용 하며 길이가 인 경우 for( in ) 에만 사용 합니다undefined .

따라서이 기능을 사용할 때 올바른 순서를 취하는 것이 안전하다고 말하고 싶습니다.

:

$(['a','b','c']).each(function() {
    alert(this);
});
//Outputs "a" then "b" then "c"

이것을 사용하는 단점은 UI 이외의 논리를 수행하면 함수가 다른 프레임 워크보다 이식성이 떨어집니다. 이 each()기능은 jQuery 선택기와 함께 사용하기에 가장 적합 for( ; ; )하며 그렇지 않은 경우 권장됩니다.



4
항상 documentcloud.github.com/underscore 가 있으며 _.each 및 기타 유용한 기능이 많이 있습니다
w00t

1
내 객체에 길이 속성이 있으면 $ .each도 실패한다는 의미입니까? 예를 들어 x = {a : "1", b : "2", 길이 : 3}입니다.
Onur Topal 2012 년

29

사용하는 루프 종류와 브라우저에 따라 성능 차이가 있습니다.

예를 들어 :

for (var i = myArray.length-1; i >= 0; i--)

일부 브라우저에서 다음보다 두 배 빠릅니다.

for (var i = 0; i < myArray.length; i++)

그러나 배열이 거대하거나 지속적으로 반복하지 않으면 모든 것이 충분히 빠릅니다. 배열 루핑이 프로젝트 (또는 그 문제에 대한 다른 프로젝트)의 병목 현상이라고 의심합니다.


5
루핑하기 전에 "myArray.length"를 변수에 저장하면 성능 차이가 사라 집니까? 내 생각은 "예"입니다.
Tomalak

3
아니요. 'myArray.length'는 객체의 메서드가 아니라 속성이므로 값을 결정하기 위해 계산이 수행되지 않습니다. 변수에 값을 저장하면 전혀 효과가 없습니다.
Jason Jason

3
그렇습니다. 속성은 변수가 아닙니다. 그들은 코드를 얻거나 설정했습니다.
ste

12
나는 사용하는 경향이있다for(var i = myArray.length; i--;)
Kevin

2
명확성과 가독성을위한 코드. 현재 시점에서 터무니없이 거대한 배열을 사용할 때 일부 브라우저에서 약간 더 빠르게 실행되는 것은 아닙니다. 최적화는 변경 될 수 있지만 코드의 가독성 (또는 그 부족)은 변하지 않습니다. 다른 사람들이 쉽게 따라갈 수있는 코드를 작성하고, 옵티마이 저가 적시에 따라 잡을 수있게하십시오.
aroth

26

네이티브 Array.forEach 메소드는 현재 폭넓게 지원되고 있습니다.


2
무엇을합니까? 다른 게시물에 언급 된 문제가 있습니까 (배열 요소 대신 속성을 반복)? 또한 IE8은이를 지원하지 않기 때문에 광범위하게 지원된다고 말할 수는 없습니다.
Rauni Lillemets

2
* nix 사용자가 그것을 멸시하는 것처럼 IE8은 대부분의 모든 하위 windows7 사용자입니다. 그것은 브라우저 시장의 거대한 부분입니다.
sbartell

2
@Rauni-요점을 지적하지만 en.wikipedia.org/wiki/Usage_share_of_web_browsers#Summary_tablemarketshare.hitslink.com/… 및 기타 사이트 에 따르면 데스크톱 장치의 경우 IE 브라우저 점유율은 40 % 미만입니다 . 브라우저의 최소 8 %는 IE 9입니다. 즉, Array.forEach는 데스크톱 브라우저의 약 70 %에서 지원되므로 '전폭적으로 지원되는'것이 부당하다고 생각하지 않습니다. 확인하지 않았지만 모바일 지원 (WebKit 및 Opera 브라우저)이 훨씬 더 높을 수 있습니다. 분명히, 지리적으로 상당한 차이가 있습니다.
Sam Dutton

1
업데이트 해 주셔서 감사합니다. 나는 그것이 "광범위하게 지원된다"고 말할 수 있음에 동의합니다. 문제는 사용자가이 JS 방법을 사용하는 경우 지원되지 않는 경우에도 백업 방법을 작성해야한다는 것입니다.
Rauni Lillemets

1
@Rauni-es5-shim 및 es6-shim을 사용하여 백업 방법을 자동으로 제공 할 수 있습니다. github.com/es-shims/es5-shim
Michiel van der Blonk

24

Chrome, Firefox, IE9, Safari 및 Opera는 모든 주요 브라우저의 2012 현재 버전에 대한 답변이 ES5의 기본 배열을 지원합니다.

IE8을 기본적으로 지원할 이유가없는 한 (적절한 JS 환경을 제공하는 ES5-shim 또는 Chrome 프레임을 이러한 사용자에게 제공 할 수 있음을 명심하십시오) 언어의 적절한 구문을 사용하는 것이 더 깨끗합니다.

myArray.forEach(function(item, index) {
    console.log(item, index);
});

array.forEach ()에 대한 전체 설명서는 MDN에 있습니다.


1
콜백의 매개 변수를 문서화해야합니다. 첫 번째 요소 값, 두 번째 요소 인덱스, 세 번째로 순회되는 배열
drewish

나는 당신이 말하는 것을 들었지만,이 경우 지나치게 단순화하면 모든 가능성을 모호하게합니다. 인덱스와 값을 모두 갖는다는 것은 키와 값을 반복하는 것을 기억할 필요가없는 보너스와 함께 for ... in 및 each ... in 모두를 대체 할 수 있음을 의미합니다.
drewish

1
@Cory : ES5 forEach를 레거시 ES3 브라우저에 상당히 쉽게 추가 할 수 있습니다. 코드가 적을수록 코드가 좋습니다.
mikemaccana

2
@nailer 배열과 객체에서 서로 바꿔 사용할 수 있습니까?
hitautodestruct

1
@hitautodestruct Object가 아닌 Array 프로토 타입의 일부입니다. 일반적으로 커뮤니티에서 현재 비 배열 객체는 여전히 'for (var key in object) {}'로 반복됩니다.
mikemaccana

14

배열이 드문 경우 두 개는 동일하지 않습니다.

var array = [0, 1, 2, , , 5];

for (var k in array) {
  // Not guaranteed by the language spec to iterate in order.
  alert(k);  // Outputs 0, 1, 2, 5.
  // Behavior when loop body adds to the array is unclear.
}

for (var i = 0; i < array.length; ++i) {
  // Iterates in order.
  // i is a number, not a string.
  alert(i);  // Outputs 0, 1, 2, 3, 4, 5
  // Behavior when loop body modifies array is clearer.
}

14

forEach를 사용하여 프로토 타입 체인 건너 뛰기

위의 @ nailer 's answer에 대한 간단한 부록 , forEach with Object.keys를 사용하면 hasOwnProperty를 사용하지 않고도 프로토 타입 체인을 반복하지 않아도됩니다.

var Base = function () {
    this.coming = "hey";
};

var Sub = function () {
    this.leaving = "bye";
};

Sub.prototype = new Base();
var tst = new Sub();

for (var i in tst) {
    console.log(tst.hasOwnProperty(i) + i + tst[i]);
}

Object.keys(tst).forEach(function (val) {
    console.log(val + tst[val]);
});

2
젠장, 비열한. 이것을 얻기 위해 50 개의 다른 게시물을 읽을 가치가있었습니다. obj = { "pink": "ducks", 빨간색 : "geese"}; Object.keys (obj) === [ "pink", "red"]
Orwellophile

14

두 번째 의견은 필요에 따라 반복 방법을 선택해야한다는 의견입니다. 난 안에 실제로 당신을 제안 이제까지 네이티브 통해 루프 Arrayfor in구조. 이 방법은 느린 체이스 Seibert는 프로토 타입 프레임 워크와 호환되지 않습니다, 전 순간에 지적.

JavaScript로 작업하는 경우 반드시 살펴 봐야 할 다양한 루핑 스타일에 대한 훌륭한 벤치 마크가 있습니다 . 초기 최적화는하지 말고 머리 뒤쪽 어딘가에 보관하십시오.

for in객체의 모든 속성을 가져 오는 데 사용 하며 스크립트를 디버깅 할 때 특히 유용합니다. 예를 들어, 익숙하지 않은 객체를 탐색 할 때이 줄을 편리하게 사용하고 싶습니다.

l = ''; for (m in obj) { l += m + ' => ' + obj[m] + '\n' } console.log(l);

전체 객체 (메소드 본문과 함께)의 내용을 내 Firebug 로그에 덤프합니다. 매우 편리합니다.


링크가 끊어졌습니다. 누군가 다른 링크가 있으면 벤치 마크를보고 싶습니다.
Billbad

더 이상 부서지지 않습니다.
Olli

프로토 타입에서 Foreach 루프가 깨지나요? 현재 일반적으로 지원되므로 프로토 타입이 해결해야 할 문제입니다.
mvrak

7

여기 내가 한 일이 있습니다.

function foreach(o, f) {
 for(var i = 0; i < o.length; i++) { // simple for loop
  f(o[i], i); // execute a function and make the obj, objIndex available
 }
}

이것은 그것을 사용하는
방법입니다. 이것은 배열과 객체 (예 : HTML 요소 목록)에서 작동합니다

foreach(o, function(obj, i) { // for each obj in o
  alert(obj); // obj
  alert(i); // obj index
  /*
    say if you were dealing with an html element may be you have a collection of divs
  */
  if(typeof obj == 'object') { 
   obj.style.marginLeft = '20px';
  }
});

방금 제안 했으므로 제안했습니다. :)


좋은 물건-꽤 간단합니다!
Chris

6

항목을 참조하려는 방식에 따라 다른 방법을 사용합니다.

현재 항목 만 원하면 foreach를 사용하십시오.

상대 비교를 수행하기 위해 인덱서가 필요한 경우에 사용하십시오. (이것은 이전 / 다음 항목과 어떻게 비교됩니까?)

성능 차이를 본 적이 없습니다. 걱정하기 전에 성능 문제가 발생할 때까지 기다립니다.


아래의 Bnos answer를 참조하십시오-for ... in은 여기에서 기대하는 일을하지 않으며 그것을 사용하면 모든 종류의 재미를 가질 수 있습니다. 레코드의 경우 프로토 타입이 올바른 방식으로 작업합니다.
marcus.greasly

4

(myArray의에서 VAR I)에 대한 당신은 할 수 루프 이상도 객체 내가 키 이름을 포함하고 당신을 통해 속성에 액세스 할 수 있습니다 [I]에서 myArray . 직접 객체의 프로토 타입에 메소드를 추가 할 경우 jQuery를 또는 프로토 타입과 같은 외부 프레임 워크를 사용하는 경우 Additionaly, 당신은 객체에 추가 한 것입니다 어떤 방법, 즉, 너무, 루프에 포함됩니다, 또는 한 지점에서 내가 가리 킵니다 그 방법.


4

조심해!

여러 스크립트 태그가 있고 예를 들어 태그 속성에서 정보를 검색하는 경우 간단한 배열이 아니라 HTMLCollection 객체이므로 for 루프와 함께 .length 속성을 사용해야합니다.

https://developer.mozilla.org/en/DOM/HTMLCollection

foreach 문을 (var i in yourList) 사용하면 대부분의 브라우저에서 HTMLCollection의 속성과 메서드가 반환됩니다!

var scriptTags = document.getElementsByTagName("script");

for(var i = 0; i < scriptTags.length; i++)
alert(i); // Will print all your elements index (you can get src attribute value using scriptTags[i].attributes[0].value)

for(var i in scriptTags)
alert(i); // Will print "length", "item" and "namedItem" in addition to your elements!

getElementsByTagName이 NodeList를 리턴해야하더라도 대부분의 브라우저는 HTMLCollection을 리턴합니다. https://developer.mozilla.org/en/DOM/document.getElementsByTagName


3

배열의 for 루프는 프로토 타입과 호환되지 않습니다. 나중에 해당 라이브러리를 사용해야 할 것으로 생각되면 for 루프를 고수하는 것이 좋습니다.

http://www.prototypejs.org/api/array


"해당 라이브러리를 사용해야 할 수도 있습니다"를 잊어 버리십시오. 대신 문제가 계속 발생하기 때문에 " JS가 해당 라이브러리를 사용하는 다른 것에 포함될 수 있습니다"라고 생각하십시오 .
ijw

3

객체와 프로토 타입 및 배열을 사용하는 "각"에 대한 문제를 보았습니다.

내 이해는 각각이 객체의 속성과 배열이 아니라는 것입니다.


3

코드 속도를 높이고 싶다면 어떻게해야합니까?

for( var i=0,j=null; j=array[i++]; foo(j) );

for 문 내에 while 논리를 사용하는 것이 다소 덜 중복됩니다. 또한 firefox에는 Array.forEach 및 Array.filter가 있습니다.


2
이것이 왜 코드 속도를 높이겠습니까? 왜 이와 같은 진술을 통해 속도를 높일 수 있는지 알 수 없습니다.
Rup

3

jsperf에 따르면 더 짧고 가장 좋은 코드는

keys  = Object.keys(obj);
for (var i = keys.length; i--;){
   value = obj[keys[i]];// or other action
}

1

병렬 처리를 이용하려면 Array (). forEach 루프를 사용하십시오.


4
브라우저의 JavaScript는 이벤트 루프 동시이므로 Array.prototype.forEach콜백에 대한 여러 호출을 병렬로 실행하지 않습니다.
Mike Samuel

1

for (;;)배열 용입니다 . [20,55,33]

for..in is for Objects : {x : 20, y : 55 : z : 33}


0

조심해!!! Mac OS에서 Chrome 22.0을 사용하고 있으며 각 구문마다 문제가 있습니다.

이것이 브라우저 문제, 자바 스크립트 문제 또는 코드의 오류인지는 모르겠지만 매우 이상합니다. 객체 외부에서는 완벽하게 작동합니다.

var MyTest = {
    a:string = "a",
    b:string = "b"
};

myfunction = function(dicts) {
    for (var dict in dicts) {
        alert(dict);
        alert(typeof dict); // print 'string' (incorrect)
    }

    for (var i = 0; i < dicts.length; i++) {
        alert(dicts[i]);
        alert(typeof dicts[i]); // print 'object' (correct, it must be {abc: "xyz"})
    }
};

MyObj = function() {
    this.aaa = function() {
        myfunction([MyTest]);
    };
};
new MyObj().aaa(); // This does not work

myfunction([MyTest]); // This works

0

둘 사이에 중요한 차이점이 있습니다. for-in은 객체의 속성을 반복하므로, 케이스가 배열 인 경우 요소뿐만 아니라 "제거"기능도 반복합니다.

for (var i = 0; i < myArray.length; i++) { 
    console.log(i) 
}

//Output
0
1

for (var i in myArray) { 
    console.log(i) 
} 

// Output
0 
1 
remove

와 함께 for-in을 사용할 수 있습니다 if(myArray.hasOwnProperty(i)). 여전히 배열을 반복 할 때 항상 이것을 피하고 for (;;) 문을 사용하는 것이 좋습니다.


0

둘 다 매우 비슷하지만 사소한 차이가 있습니다.

var array = ["a", "b", "c"];
array["abc"] = 123;
console.log("Standard for loop:");
for (var index = 0; index < array.length; index++)
{
  console.log(" array[" + index + "] = " + array[index]); //Standard for loop
}

이 경우 출력은 다음과 같습니다.

루프 표준 :

배열 [0] = A

ARRAY [1] = B

배열 [2] = C

console.log("For-in loop:");
for (var key in array)
{
  console.log(" array[" + key + "] = " + array[key]); //For-in loop output
}

이 경우 출력은 다음과 같습니다.

사전 루프 :

ARRAY [1] = B

배열 [2] = C

배열 [10] = D

배열 [ABC] = 123


0

for in 문을 사용하면 객체의 모든 속성 이름을 반복 할 수 있습니다. 불행히도 프로토 타입 체인을 통해 상속 된 모든 멤버를 반복합니다. 이것은 관심이 데이터 멤버에있을 때 메소드 함수를 제공하는 데 나쁜 부작용이 있습니다.

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