이번 포스팅의 목적은 다음과 같습니다.
1. 타입이 마구 변하는 JS 객체의 프로퍼티를 어떻게 빨리 읽어내는가에 대한 호기심 해결
2. 이왕이면 불필요한 동적 타이핑 남발을 자제하며 최적화할 수 있는 관점 생각해보기
0⬛⬛ 1⬜⬜⬜2⬛⬛⬛
기본적으로 객체의 프로퍼티에 접근하면 객체의 기준 메모리 주소와 상대적인 값인 오프셋을 통해 값을 읽어냅니다. 각각의 오프셋은 들어올 데이터 타입을 통해 결정합니다. (number: 8byte, string: 문자열 참조값...)
→ 동적 탐색을 회피하고자 V8엔진은 히든 클래스를 사용해 객체의 구조(오프셋 값)을 저장합니다.
히든 클래스는 V8엔진에서 사용하는 데이터로 객체의 구조(프로퍼티의 오프셋)와 히든클래스 전환에 대한 정보를 담고 있습니다. 자바스크립트의 '클래스' 개념과의 혼란을 막기 위해 shape라고도 불립니다.
function Student(name, age, grade) {
this.name = name; //2
this.age = age; //3
this.grade = grade; //4
}
var Jim = new Student("jim", 19, 'A'); //1
var Mary = new Student("Mary", 25, 'c'); //5
var Karin = new Student("Karin", 25, ['B','C']); //6
위의 예제에서 Student 생성자 함수에 대한 인스턴스 3개를 new 연산자를 이용해 생성했습니다. Jim, Mary에서는 grade 프로퍼티 값으로 문자열을 넣어주었지만 세번째 인스턴스 Karin에서 배열['B','C']로 넣었습니다.
아래는 히든 클래스가 생성되는 과정입니다.
해당 생성자 함수를 호출해서 인자를 하나씩 넣어줄 때마다 히든 클래스가 생성되고, 생성된 히든클래스를 연결하고 있습니다. name, age, grade 값이 스트링, 숫자, 스트링인 Student메서드는 바로 히든클래스의 객체 구조에 접근할 수 있습니다.
C4에서는 grade를 위한 매개변수의 인자에 배열을 넣어주자 새로운 히든 클래스를 사용하는 것을 볼 수 있습니다.
객체 프로퍼티의 수, 순서, 데이터타입이 변할 때 마다 새로운 히든 클래스를 생성한다.
도입부에서 언급했듯 이번 포스팅은 히든 클래스가 JS 객체를 읽어낼 때 어떻게 최적화를 하는지에 대한 개인적인 호기심을 해결하기 위한 것입니다.
V8 엔진의 깊은 원리까지는 알아볼 수 없었지만 궁금했던 부분을 조금이나마 해결할 수 있는 주제였습니다.
다음은 히든 클래스의 개념을 이해하고 할 수 있는 최적화 관점에서의 행동 지령입니다 :)
👉 객체를 다룰 때 프로퍼티 순서를 동일하게 처리 하자 (불필요한 히든 클래스 생성 방지)
👉 객체를 생성할 때 프로퍼티 초기화도 같이하자
👉 불필요하게 객체의 프로퍼티 데이터타입 및 순서, 갯수를 가능한 변경하지 말자
👉 (내 생각) 타입스크립트를 사용할 수 있다면 왠만하면 사용하자
Franziska Hinkelmann: JavaScript engines - how do they even? | JSConf EU
좋은 글 감사합니다. 특히나 생성자를 만들어서 메모리 탭 스냅샷을 찍고 하나하나 캡쳐해주신게 이해에 도움이 많이 됐습니다!