~에 대한 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_table 및 marketshare.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

두 번째 의견은 필요에 따라 반복 방법을 선택해야한다는 의견입니다. 난 안에 실제로 당신을 제안 이제까지 네이티브 통해 루프 Array와 for 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.