자바스크립트 loop 순회 순서에 대해서 질문드립니다

안녕하세요 자바스크립트 순회라고 하면

  • for… in 문
  • for… of 문
  • Array.prototype.forEach (기타 map, reduce, filter 등…)

보통 위와 같은데

제가 해당 키워드를 잘 찾지 못하는걸수도 있지만…

아래 제가 찾아본바에 따르면, index가 없는 Arraylike 객체는 순서가 보장이 안되는것 같은데 그렇기때문에 객체 프로퍼티를 이용해 순회하는 for… in 문의 순서가 보장이 되지 않는 건가요?

for of문은 이터레이터 프로토콜을 사용해 순회순서가 보장될것은 같습니다만… 그것이 객체가 되면 어찌 되는것인지
그외에 메소드이 순회순서가 보장되는지 궁금합니다
(es5, es6때 정보가 섞여서 그런것인지…)

혹시 제가 잘못 이해한점이나, 관련 링크 있으시다면 공유 부탁드립니다. 자세히 알려주시면 더 감사하겠습니다 :smiley:

감사합니다!


mdn 에 for … in 문 설명입니다

“A for...in loop iterates over the properties of an object in an arbitrary order”

아래는 mdn Object.keys example 입니다

// array like object with random key ordering
const anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj)); // console: ['2', '7', '100']

이미 알아보신대로, 객체를 for...in으로 순회 시, 프로퍼티 등록 순서를 보장하지 않습니다. 이것은 전적으로 JS 엔진 구현에 따르며, 엔진 내부적으로 순서를 정해 두었다 하더라도 JS 공식적인 문서상으로 arbitrary 하다고 명시하고 있습니다.

참고로 현재 ECMAScript 2015를 따라 구현된 JS 엔진에서는 stringSymbol로 추가된 속성에 대해서는 그 순서를 보장하고 있습니다.
그래도 몇몇 이슈가 있긴 해서(정수형 인덱스와 혼합된 객체의 순서 보장 문제, delete 부작용)
등록된 순서를 보장되는 자료구조를 필요로 한다면 대체재로 Map을 쓰고 for...of 로 순회하는 것을 권하고 있습니다.


P.S.1

JS에서 array-like 객체라고 하면,
속성으로 length가 있고 개별 값으로 정수형 인덱스 접근이 가능하나
Array의 프로토타입 메소드들이 존재하지 않는 것을 말합니다.
(이 설명도 정확한건 아닙니다만… 아무튼,)
JS 프로그래밍 과정중에서 종종 보게 될 array-like 객체는
보통 정수로 인덱싱 되어 있으므로
for (var i = 0; i < array_like.length; i++)문으로 인덱스 순서를 보장받을 수 있겠죠.
만약 해당 array-like 객체가 이터러블 프로토콜을 만족시킨다면
(e.g. arguments, HTMLCollection, NodeList)
for...of로도 순회가 가능할겁니다.

임의로 만든 array-like 객체를 보시면,

const a = {};
a.prop2 = 'prop2';
a.prop1 = 'prop1';
a[3] = 3;
a[1] = 1;
a[0] = 0;
a.length = 4;

for (let p in a)
    console.log(p);
/*
0
1
3
prop2
prop1
length
*/

string 타입의 키 값은 넣는 순서를 보장합니다.
정수형 키 값은 오름차순으로 정렬되며 순회 시 string형 보다 먼저 접근됩니다.
(주의: 경우에 따라 아닐 수도 있습니다.)

여기에 iterator 프로토콜을 만족하도록 Symbol 속성을 추가하면
마치 배열인 것처럼 for...of 로 순회 가능하며 인덱스 순서를 보장받을 수 있습니다.
정수형 속성이 아닌 값들은 무시되고요.

// iterator 구현까지는 좀 귀찮으므로 Array의 iterator를 빌려 쓰자.
a[Symbol.iterator] = Array.prototype[Symbol.iterator];

for (let v of a)
    console.log(v);
/*
0
1
undefined
3
*/

질문에서 언급하신

는 제가 이해를 잘못한 것이 아니라면
문맥상으로 오해의 소지가 있는 표현 같습니다.


P.S.2

JS에서 배열은 연속된 메모리에서 특정 주소값으로부터의 offset으로 값을 접근할 수 있는 자료구조가 아닙니다. (그것과 유사한 개념을 원하신다면 TypedArray를 살펴 보세요.)
K-V 컬렉션으로 이해하시는게 오히려 쉬울 수 있습니다.
JS의 Array 특징과 관련하여(정수형 인덱스와 Array.length와의 관계, empty slot, 등등) 이 곳 jsdev에서 한 차례 논의 된 바 있었습니다. 아래 링크를 참고해 보세요.

1개의 좋아요

array-like에 대해 잘못알고 있었군요… :frowning_face:

새로운 사실 알아갑니다. 더 찾아봐야하겠네요…

답변해주신대로, 순서보장을 원하면 for…of문을 사용하는게 좋을것 같습니다

친절한 설명 감사합니다 :smiley: