"for (… in…)"루프의 요소 순서


205

Javascript의 "for… in"루프는 해시 테이블 / 요소를 선언 된 순서대로 반복합니까? 순서대로하지 않는 브라우저가 있습니까?
사용하려는 객체가 한 번 선언 되고 수정되지 않습니다.

내가 가지고 있다고 가정 해보십시오.

var myObject = { A: "Hello", B: "World" };

그리고 나는 그들을 더 사용합니다 :

for (var item in myObject) alert(item + " : " + myObject[item]);

가장 괜찮은 브라우저에서 'A : "Hello"가 항상'B : "World" '앞에 올 것으로 기대할 수 있습니까?


61
그들은 잠재적 인 브라우저 및 변형의 하위 집합 만 테스트하기 때문입니다. 미래의 브라우저는 말할 것도 없습니다. 비 실패 테스트가 확실한 증거를 제공한다고 가정하는 것은 잘못입니다.
James Hughes

6
내 자신의 제한된 자바 스크립트 능력이 SO 군중보다 낫다는 것을 의심합니다. 누가 이상한 브라우저가 숨어 있는지 알고 있습니까? 그리고 당신은 대답에서 GChrome에 간단한 예제 사례에서는 분명하지 않은 버그가 있음을 알 수 있습니다.
chakrit


답변:


214

인용 존 레식 :

현재 모든 주요 브라우저는 객체의 속성을 정의 된 순서대로 반복합니다. Chrome은 몇 가지 경우를 제외하고이 작업도 수행합니다. [...]이 동작은 ECMAScript 사양에 의해 명시 적으로 정의되어 있지 않습니다. ECMA-262의 섹션 12.6.4 :

속성을 열거하는 메커니즘은 구현에 따라 다릅니다.

그러나 사양은 구현과는 다릅니다. ECMAScript의 모든 최신 구현은 정의 된 순서대로 객체 속성을 반복합니다. 이 때문에 Chrome 팀은이 버그로 간주하여 수정합니다.

모든 비 숫자 속성 이름에 대해 수행하는 Chrome 및 Opera를 제외한 모든 브라우저는 정의 순서 따릅니다. 이 두 브라우저에서 속성은 숫자가 아닌 첫 번째 속성보다 순서대로 가져옵니다 (배열을 구현하는 방법과 관련이 있음). 순서도 동일 Object.keys합니다.

이 예제는 어떤 일이 발생하는지 명확히해야합니다.

var obj = {
  "first":"first",
  "2":"2",
  "34":"34",
  "1":"1",
  "second":"second"
};
for (var i in obj) { console.log(i); };
// Order listed:
// "1"
// "2"
// "34"
// "first"
// "second"

이것의 기술은 이것이 언제라도 변할 수 있다는 사실보다 덜 중요합니다. 이런 식으로 머무는 것에 의존하지 마십시오.

간단히 말해 : 순서가 중요한 경우 배열을 사용하십시오.


3
실제로는 아닙니다. Chrome은 다른 브라우저와 동일한 순서를 구현하지 않습니다 : code.google.com/p/v8/issues/detail?id=164
Tim Down

19
"주문이 중요한 경우 배열을 사용하십시오": JSON을 사용하는 경우는 어떻습니까?
HM2K

11
@ HM2K도 마찬가지입니다. 스펙은 "객체는 0 개 이상의 이름 / 값 쌍의 정렬되지 않은 모음입니다." JSON은 자바 스크립트가 아닙니다 : 서버는 사용자가 전달한 순서를 존중할 필요가 없으며 아마도 없을 수도 있습니다.
Borgar 2019

7
21 버전 이후의 Firefox는 더 이상 삽입 순서를 존중하지 않는 것 같습니다.
Doc Davluz

2
이 답변은 ES2015에서 거짓입니다.
Benjamin Gruenbaum

54

1 년 후이 문제를 범핑하는 중 ...

그것은이다 2012 및 주요 브라우저는 여전히 차이 :

function lineate(obj){
    var arr = [], i;
    for (i in obj) arr.push([i,obj[i]].join(':'));
    console.log(arr);
}
var obj = { a:1, b:2, c:3, "123":'xyz' };
/* log1 */  lineate(obj);
obj.a = 4;
/* log2 */  lineate(obj);
delete obj.a;
obj.a = 4;
/* log3 */  lineate(obj);

현재 브라우저에서 요점 또는 테스트

Safari 5, Firefox 14

["a:1", "b:2", "c:3", "123:xyz"]
["a:4", "b:2", "c:3", "123:xyz"]
["b:2", "c:3", "123:xyz", "a:4"]

Chrome 21, Opera 12, 노드 0.6, Firefox 27

["123:xyz", "a:1", "b:2", "c:3"]
["123:xyz", "a:4", "b:2", "c:3"]
["123:xyz", "b:2", "c:3", "a:4"]

IE9

[123:xyz,a:1,b:2,c:3] 
[123:xyz,a:4,b:2,c:3] 
[123:xyz,a:4,b:2,c:3] 

16
여기서 무슨 문제가 있습니까? 사양에 따르면 정확히 정렬되지 않은 키 / val 쌍의 목록입니다.
nickf

5
nickf : 구현은 스펙이 말한 것을 수행한다는 점에서 옳습니다. 나는 모든 사람들이 자바 스크립트 사양이 ... : P
박스

10
@boxed : 객체를 해시 맵 (테이블 / 무엇이든)으로 생각하십시오. 대부분의 언어 (Java, Python 등)에서 이러한 종류의 데이터 구조는 정렬되지 않습니다. 따라서 이것이 JavaScript에서도 마찬가지인 것은 놀라운 일이 아니며 사양을 잘못하거나 어리석게 만들지는 않습니다.
Felix Kling

9
솔직히이 대답의 요점을 알지 못합니다 (죄송합니다). 속성이 반복되는 순서는 구현 세부 사항이며 브라우저는 서로 다른 JavaScript 엔진을 사용하므로 순서가 다를 것으로 예상됩니다. 변경되지 않습니다.
Felix Kling

2
최신 구현에서는 실제 배열에 의해 지원되므로 숫자 값 순서로 정수 특성을 수신하고 숨겨진 클래스 / 형태 구성으로 인해 명명 된 특성이 삽입 순서로 수신됩니다. 변할 수있는 것은 정수 속성을 먼저 나열하거나 명명 된 속성을 먼저 나열하는지 여부입니다. delete최소한 V8에서는 해시 테이블에 의해 오브젝트가 즉시 백업되기 때문에 추가 가 흥미 롭습니다. 그러나 V8의 해시 테이블은 삽입 순서로 저장됩니다. 여기에서 가장 흥미로운 결과는 IE입니다. 나는 그것을
풀기

27

로부터 인 ECMAScript 언어 사양 (온 섹션 12.6.4 for .. in루프) :

속성을 열거하는 메커니즘은 구현에 따라 다릅니다. 열거 순서는 개체에 의해 정의됩니다.

4.3.3 절 ( "객체"의 정의) :

순서가없는 속성 모음으로 각각 기본 값, 객체 또는 함수를 포함합니다. 객체의 속성에 저장된 함수를 메서드라고합니다.

JavaScript 구현에서 일관된 순서로 열거되는 속성에 의존 할 수 없다는 것을 의미합니다. (어쨌든 언어의 구현 별 세부 사항에 의존하는 것은 나쁜 스타일입니다.)

주문을 정의하려면 객체에 액세스하기 전에 정렬하는 키 배열과 같이 주문을 정의하는 것을 구현해야합니다.


10

for / in 열거하는 객체의 요소는 DontEnum 플래그가 설정되지 않은 속성입니다. ECMAScript (일명 Javascript) 표준은 명시 적으로 "객체는 정렬되지 않은 속성 모음"입니다 ( http://www.mozilla.org/js/language/E262-3.pdf 섹션 8.6 참조 ).

모든 Javascript 구현이 선언 순서대로 열거된다고 가정하는 것은 표준을 준수하는 것 (즉, 안전)이 아닙니다.


2
그래서 그는 단지 다음과 같이 가정하는 대신 질문을합니다. p
Jamie Pate

4

반복 순서는 속성 삭제와 관련하여 혼동되지만이 경우 IE에서만 혼동됩니다.

var obj = {};
obj.a = 'a';
obj.b = 'b';
obj.c = 'c';

// IE allows the value to be deleted...
delete obj.b;

// ...but remembers the old position if it is added back later
obj.b = 'bb';
for (var p in obj) {
    alert(obj[p]); // in IE, will be a, bb, then c;
                   // not a, c, then bb as for FF/Chrome/Opera/Safari
}

http://code.google.com/p/v8/issues/detail?id=164 에서 논의 가 표시 되는 경우 반복 순서를 수정하기 위해 사양을 변경하려는 욕구는 개발자들 사이에서 매우 인기있는 욕구처럼 보입니다 .


3

IE6에서는 순서가 보장되지 않습니다.


2

주문을 신뢰할 수 없습니다. Opera와 Chrome은 모두 정렬되지 않은 속성 목록을 반환합니다.

<script type="text/javascript">
var username = {"14719":"A","648":"B","15185":"C"};

for (var i in username) {
  window.alert(i + ' => ' + username[i]);
}
</script>

위의 코드는 Opera의 B, A, C 및 Chrome의 C, A, B를 보여줍니다.


1

이것은 그 자체로 질문에 대답하지 않지만 기본 문제에 대한 해결책을 제공합니다.

보존 순서에 의존 할 수 없다고 가정하면 키와 값이 속성으로 된 객체 배열을 사용하지 않는 이유는 무엇입니까?

var myArray = [
    {
        'key'   : 'key1'
        'value' : 0
    },
    {
        'key'   : 'key2',
        'value' : 1
    } // ...
];

이제 키가 고유한지 확인해야합니다 (이것이 또한 중요하다고 가정 할 때) 직접 주소 지정 변경 사항 및 for (... in ...)는 이제 인덱스를 '키'로 리턴합니다.

> console.log(myArray[0].key);
key1

> for (let index in myArray) {console.log(myArray[index].value);}
0
1
펜보기 위해 주소 (...에 ...)를 들어 JDQ (가 @JDQ 에) CodePen .

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