본문 바로가기

Develop/Frontend 가이드

[FE] JavaScript 완벽 가이드, ECMAScript 를 읽는 방법 (2/2)

반응형

TC39
TC39

JavaScript 완벽 가이드, ECMAScript 을 읽는 방법

저번 글 에서는 ECMAScript 를 읽기 위해 알아야 할 개념들을 소개했고, 이번 글에서는 ECMAScript 문서에서 자바스크립트 동작 원리를 파악하는 과정을 소개하도록 하겠습니다.

const o1 = { foo: 99 };
const o2 = {};
Object.setPrototypeOf(o2, o1);
o2.foo;
// → 99

위 코드를 보면 Object.setPrototypeOf(o2, o1) 을 호출해서 o2 의 프로토타입을 o1 으로 설정했습니다. o2 의 프로토타입이 o1 이 되었기 때문에 o2foo 라는 속성이 없어도 o2.fooo1.foo 에 접근하여 값을 얻어 마지막 코드 o2.foo 의 결과가 o1.foo 의 값과 동일한 99 가 됩니다.

위와 같은 동작을 자바스크립트 용어로 프로토타입 체인 이라 하며, 프로토타입 체인의 원리는 ECMAScirpt 문서에 정의되어 있습니다.

프로토타입 체인

저번 글의 'Ordinary' Object vs 'Exotic' Object 문단에서 설명했듯이, 모든 Object 는 ECMAScript 에 정의된 Essential Internal Methods 를 가지고 있습니다. Essential Internal Methods 중 프로토타입 체인의 동작 원리와 관련하여 자세히 살펴봐야 하는 함수는 [[Get]] 입니다. [[Get]] 함수는 Object 의 속성에 접근할 수 있는 함수입니다. 그리고 Ordinary Object 는 [[Prototype]] 이라는 Internal Slot 을 가지고 있습니다. 자바스크립트의 프로토타입 체인은 Internal Methods [[Get]] 과 Internal Slot [[Prototype]] 을 이용해서 동작합니다. 위에서 제공한 예제 코드을 바탕으로 구체적으로 설명드리도록 하겠습니다.

먼저 o2.foo; 는 개발자가 작성한 문자열에 불과합니다. o2.foo; 문자열은 ECMAScript 문서에 정의된 대로 자바스크립트 엔진에 의해 해석되고 ECMAScript 에 정의된 절차대로 동작해야 의미를 가집니다. 그렇다면 자바스크립트는 문자열 o2.foo; 를 어떻게 해석할까요?

ECMAScript 문서 중 문법에 대한 해석 일부
ECMAScript 문서 중 문법에 대한 해석 일부

ECMAScript 문서 중 자바스크립트 문법의 표현을 어떻게 받아들일지를 정의한 Expressions 에 따르면 o2.foo; 는 'MemberExpression.IdentifierName' 형태로 MemberExpression 에 해당합니다. o2['foo']; 도 'MemberExpression.[Expression]' 형태이기 때문에 MemberExpression 에 해당합니다.

ECMAScript 에 정의된  MemberExpression 해석 절차
ECMAScript 에 정의된  MemberExpression 해석 절차

자바스트립트 엔진은 MemberExpression 을 Runtime Semantics 에 정의된 절차대로 진행하게 됩니다. Runtime Semantics 은 해석된 문법을 런타임에 어떻게 처리할지를 절차로 정의한 내용이고, MemberExpression 에 대한 처리 절차는 위 그림과 같습니다. 위 절차 중 2번 절차 'Let baseValue be ? GetValue(baseReference)' 를 따라가면, Object 의 Internal Methods 중 하나인 [[Get]](P, Recevier) 함수를 호출하게 됩니다.


GetValue 함수에 전달하는 baseReference 는 Specification Types 중 하나인 Reference Record 타입으로 다음 표와 같은 속성을 가집니다.

Field NameMeaning
[[Base]]Environment Record 로, 클로저의 Lexical Environment 와 관계된 데이터입니다. 'o2.foo;' 의 경우 전역 환경에서 실행되므로 Global Environment Record 가 됩니다.
[[ReferencedName]]참조 이름을 표현한 String 데이터로, 'o2.foo;' 의 'foo' 입니다.
[[Strict]]자바스크립트가 Strict 모드에서 실행되는지를 Boolean 으로 나타나는 데이터입니다. 'o2.foo;' 의 경우 'false' 입니다.
[[ThisValue]]자바스크립트에서 사용하는 'this' 에 대한 데이터입니다. 'o2.foo;' 에서 'o2' 입니다.

GetValue(V) 절차
GetValue(V) 절차

MemberExpression 을 처리하는 절차 중 호출한 GetValue(V) 절차 중 4.b 번에서 Object baseObj 의 속성을 접근하는 Internal Methods 인 [[Get]](P, Recevier) 를 호출합니다.


자바스크립트의 'this' 를 결정하는 Abstract Operations
자바스크립트의 'this' 를 결정하는 Abstract Operations

[[GetValue(V)]] 의 절차 중 4.b 에서 'GetThisValue(V)' 함수를 호출하고 있습니다. 'GetThisValue(V)' 은 자바스크립트에서 자주 사용되는 this 를 결정해서 반환하는 함수이며, Object 의 Internal Methods 인 [[Get]](P, Recevier)Receivier 에 해당합니다.


지금까지 o2.foo; 에 대한 문법 해석부터 Object 의 [[Get]](P, Recevier) 함수를 호출했는지를 살펴봤습니다. 이제 자바스크립트에서 Object 의 속성을 어떻게 찾아서 반환하는지를 살펴봅시다.

ECMAScript 내 [[Get]] 함수
ECMAScript 내 [[Get]] 함수

먼저 [[Get]](P, Recevier) 함수 정의를 보면 Property Key 인 PReceiver 를 변수로 받아, OrdinaryGet(O, P, Receiver) 을 호출하고 결과를 반환합니다. [[Get]](P, Recevier) 함수의 PGetValue 함수를 호출할 때 전달한 V.[[ReferencedName]]foo 가 되고, Receiver 의 경우 GetThisValue(V) 의 반환값인 o2 가 됩니다.

ECMAScript 내 OrdinaryGet 함수
ECMAScript 내 OrdinaryGet 함수

OrdinaryGet(O, P, Receiver) 함수는 2번 절차에서 원하는 속성이 있는지를 확인하고 원하는 속성이 없으면, 3번 절차를 진행합니다. 3번 절차에서는 O.[[GetPrototyupeOf]]() 를 호출해 Internal Slot 인 [[Prototype]] 을 얻어서 [[Prototype]][[Get]](P, Receiver) 를 호출합니다.

o2.foo; 를 가지고 설명하자면,

o2OrdinaryGet(O, P, Receiver) 호출에선 o2foo 속성이 없으므로 3번 절차를 진행하게 되고, o2 의 프로토타입인 o1[[Get]](P, Receiver) 를 호출합니다.

o1OrdinaryGet(O, P, Receiver) 호출에선 o1foo 속성이 있으므로 o1.foo 값인 NormalCompletion(99) 를 반환합니다.

o2OrdinaryGet(O, P, Receiver)o1OrdinaryGet(O, P, Receiver) 호출 결과인 NormalCompletion(99) 을 반환하고 종료합니다.

결과

결국 자바스크립트의 프로토타입 체인OrdinaryGet(O, P, Receiver) 에 정의되어 있다고도 할 수 있습니다.

만약 Ordinary Object 가 아닌 Exotic Object 라면 [[Get]](P, Recevier)OrdinaryGet(O, P, Receiver) 를 호출하지 않고 다르게 동작할 수도 있습니다.

ECMAScript 문서에는 이 글에서 설명한 프로토타입 체인만이 아니라, 자바스크립트에 대한 많은 인사이트를 얻을 수 있습니다. 저 또한 이번에 글을 작성하면서 개념적으로만 알고 있던 자바스크립트에 대해 많은 걸 배울 수 있었습니다. ECMAScript 문서를 읽는게 당장 개발에 도움이 되지 않을진 몰라도, 프론트 엔드 개발자로 기본을 탄탄히 할 수 있는 문서이므로 꾸준히 읽어 나갈 예정입니다.

참고

How to Read the ECMAScript Specification
Understanding the ECMAScript spec

반응형