객체 프로퍼티 키 평가 과정
Lee Dogeon @moreal@hackers.pub
AI도 무조건 틀리는 Javascript 퀴즈 (Hackers' Pub 글)을 풀어보면서 알게된 것을 적어보는 글입니다. 사실... 알고보니 간단한 곳에서 끝나는 이야기였지만 그래도 메모삼아 남겨놓습니다 🫠
예제 코드 돌려보기
원 글의 코드를 인용하면 아래와 같습니다.
const age = {
ruby: 18,
ayumu: 19,
siki: 20
}
const preferences = {
ruby: ["mint chocolate", "you"],
ayumu: ["strawberry", "you"],
siki: ["cookie and cream", "you"]
}
["ruby", "ayumu", "siki"].forEach(printAge)
function printAge(name) {
console.log(`${name} is ${age[name]}`)
}
일단 눈으로 볼 때는 ruby is 18
같은 꼴로 쭉 나올 것 같습니다. 그래서 뭐지 해서 돌려보니 예상과 다르게 아래와 같은 결과가 나왔습니다.
cookie and cream is undefined
you is undefined
처음에는 당황했는데 세미콜론이 없어 {...}[...].forEach(...)
같은 꼴로 처리가 된 것이었습니다.
Symbol.toPrimitive
세미콜론이 없어서 {...}[...]
같은 꼴로 이어 붙은 것은 이해했지만 ["ruby", "amuyu", "siki"]
같이 여러 값이 주어지는데 이게 요소에 접근이 되는 것이 잘 이해가 가지 않았습니다. 그래서 코드를 이래저래 만지다가 다른 것을 찾아봤는데 결론부터 이야기하면 자바스크립트에는 comma가 튜플로 동작하지 않고, comma로 이어진 표현식들 중 마지막 표현식의 평가값이 리턴되도록 해서 동작하므로 "siki"
가 키로 사용되어 관련 값들이 출력된 것이었습니다.[1]
> console.log((1, 2, 3))
3
아무튼 이걸 인지 못 하고 별개로 코드를 만져보다가 아래와 같은 코드도 동작하는 것을 알게 되었습니다.
console.log({foo: 1, bar: 2}[[[[[["foo"]]]]]]) // 1
console.log({foo: 1, bar: 2}[[[["foo"]]], [[[["bar"]]]]]) // 2
배열이 프로퍼티 키로 들어갈 수 있다는 것이 다소 이해가 가지 않았습니다. 들어갈 수는 있겠으나 그에 상응하는 값이 없을테니 undefined
를 반환하는 것이 맞다고 생각했습니다. 관련하여 명세가 어떻게 되어있는지 찾아봤습니다.
찾아본 과정을 기록하고 싶어서 링크를 모두 나열해봤는데 너무 길어져서 접어놓았습니다.
- https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-property-accessors
프로퍼티에 접근하는 방식에 대한 문법을 설명합니다. - https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-property-accessors-runtime-semantics-evaluation
프로퍼티에 접근하는 것이 런타임에서 어떻게 동작해야 하는지 설명합니다. - https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-evaluate-property-access-with-expression-key
EvaluatePropertyAccessWithExpressionKey
의 동작 - https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-getvalue
GetValue
의 동작- https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#property-key
property key
term에 대한 설명 - https://tc39.es/ecma262/multipage/abstract-operations.html#sec-topropertykey
ToPropertyKey
의 동작
- https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#property-key
간단히 적으면 ...[key]
꼴로 프로퍼티에 접근할 때 key
를 property key
로 변환하는데 이때 Symbol.toPrimitive
가 있다면 이를 활용하고 아니라면 toString
, valueOf
를 사용합니다. 자바스크립트에서는 [["foo"]].toString()
의 값은 "foo"
와 같으므로 위 예제 코드가 동작하는 것입니다.
Symbol.toPrimitive
를 활용하면 객체가 property key로 사용될 때 객체가 어떻게 평가되어야 하는지 정의할 수 있습니다. 아래와 같이 사용하면 "foo"
프로퍼티에 접근할 수 있습니다.
> console.log({foo: 1, bar: 2}[{ [Symbol.toPrimitive]() { return "foo" } }]);
1
마무리 및 관련 자료
정답(?)은 간단한 거였고 관련 없는 걸 찾아본 꼴이 되었지만 새로운 걸 알게된 게 좋아서 메모 겸 적어보았습니다. 그리고 위 같은 기묘한 코드는 사실 유효한 동작이면 안 되는 것 같지만, 아마 제가 모르는 용도가 어딘가 있을거라 생각하며 마무리 지어봅니다.
- Automatic Semicolon Insertion
Symbol.toPrimitive
: 위 접어놓은 링크들.