본문 바로가기

자바스크립트

Object.keys()는 넣은 순서대로 나오는 걸까?

전봇대 위의 참새. Unsplash 에 Nagara Oyodo 님이 올림.

요약

좀 다름

들어가는 말

자바스크립트는 온 세상이 객체라고 해도 될 정도이긴 하지만, 객체의 활용법 중 하나는 마치 파이썬의 dictionary처럼 key-value 쌍으로 이루어진 저장소를 사용할 수 있다는 점입니다.

const score = {
  korean: 30,
  math: 20,
  english: 10,
};

 

이런 식으로요.

 

여기에서 만약 key 값들만을 원한다면 Object.keys(score) 이런 식으로 가져올 수 있겠죠. 이 때 나오는 배열의 순서는 어떨까요? 크게 세 가지 선택지가 있을 것 같아요.

 

  1. 적은 순서대로 나온다. ['korean', 'math', 'english']
  2. 가나다 순서대로 나온다. ['english', 'korean', 'math']
  3. 매번 무작위로 섞여서 나온다.

실제 코드를 돌려보면 적은 순서대로 나옵니다. 하지만 이번에만 그런 것이지, '적은 순서대로 나온다'는 말은 틀렸습니다.

 

const score = {
  korean: 30,
  math: 20,
  english: 10,
  1234: 0,
};

console.log(Object.keys(score));

 

이렇게 살짝 바꾸면 결과는 ['1234', 'korean', 'math', 'english'] 입니다. 단순한 시간 순서가 아니라는 말이죠.

실제 규칙

정말 놀랍게도 ECMAScript Spec에는 그 알고리즘이 기술되어 있습니다. 요약하면 크게 세 단계로 나누어지는데요.

 

  1. array index 들을 맨 앞에, 오름차순으로 정렬
  2. array index 가 아닌 String 친구들을 시간 오름차순으로 정렬
  3. Symbol 들을 시간 오름차순으로 정렬

객체의 key 중 array index 라는 친구들이 먼저 오름차순으로 오고, 그 다음에 문자열은 넣은 순서대로, 마지막으로 심볼들이 넣은 순서대로 오네요.

array index

객체는 배열이 아닌데 array index 라는 건 도대체 뭘 말하는 걸까요? 우선 자바스크립트 객체의 key 값으로는 문자열 또는 심볼만 올 수 있으니 array index 역시 일종의 문자열입니다. 위쪽 예제에서 짐작하신 분들도 있겠지만 array index 는 쉽게 말하면 '숫자같은 문자열' 입니다.

 

이 정의 역시 ECMAScript Spec에 나와 있는데요. CanonicalNumericIndexString(n) 의 결과가 +0 이상 2^32-2 이하인 경우라고 합니다. 이쪽도 파고 들어가면 자바스크립의 실제 문법 구조까지 나올 정도로 들어갈 수 있지만 저는 발만 담그고 얼른 빠져나왔습니다. CanonicalNumericIndexString(n)은 주어진 문자열 nToString 하고 다시 ToNumber 한 결과가 정확히 n과 일치하면 숫자를, 아니면 undefined를 반환합니다. 이진법을 표현한 문자열이라면 ToNumber의 결과가 십진법이니까 정확히 일치하지 않아요. 정말 십진법 숫자처럼 생긴 애들만 인정해줍니다.

 

주어진 문자열을 딱 봤을 때 십진수처럼 보인다면 array index라고 생각하는 게 편할 지도 모르겠네요.

예제

const test = {
    qwer: null,
    asdf: null,
    0b10: null,
    1: null,
    '0b10': null,
};

console.log(Object.keys(test));

 

결과는 ['1', '2', 'qwer', 'asdf', '0b10'] 입니다.

 

1은 당연히 array index.


0b10은 좀 복잡한데요. 객체로 주어진 key가 문자열 또는 심볼이 아니라면 객체 생성 시ToPropertyKey를 사용해서 변환 후에 넣는 것으로 보입니다. 그러면 애초에 들어갈 때부터 0b10이 아니라 2로 들어갔고, 이건 array index 가 맞죠.


나머지는 문자열이니 넣은 순서대로 갑니다.

참고) unordered set과 ordered set

결과적으로 자바스크립트 객체의 key 값들의 순서는 우리가 조종할 수 있는 부분이 아닙니다. Object.keys는 나름의 정렬 방식은 있지만 그 결과를 저희가 원하는 대로 바꿀 수는 없으니까요. 그래서 객체는 unordered set입니다.

반대로 Set이나 Map은 값들을 순회할 때 무조건 넣은 순서대로 받을 수 있는데요. 이 친구들은 ordered set 이라고 부릅니다.

결론

Object.keys의 결과물은 나름의 순서가 있지만 완벽한 시간 순은 아니다.

참고 자료

OrdinaryOwnPropertyKeys
array index
CanonicalNumericIndexString
ToNumber
ToString
ToPropertyKey
Object initializer runtime semantics