- 리터럴이란?
소스코드의 고정된 값을 나타내는 표기법, 예를 들어 ‘5’, ‘”Hello”’, ‘true’ 같은 코드 내에서 일반적으로 우변에 들어가는 실질 값을 말합니다.
- 객체 리터럴?
자바스크립트에서 대부분의 변수는 객체로 정의하게 됩니다. 그래서 편의성을 위해 리터럴을 통한 생성를 지원합니다. 객체를 생성해 변수에 대입하는 방법은 객체 리터럴 이외에도 다양하게 많습니다. (생성자 함수나 팩토리 함수 등)
let person = { name: "John", age: 30, greet: function() { console.log("Hello, " + this.name); } }; person.age // 30 person.greet(); // "Hello, John" delete person.name; // { age: 30, greet: function }
{}
표기가 객체 리터럴에서 한 객체를 알리는 표현이며, 한 객체는 여러개의 프로퍼티를 가질 수 있습니다. 프로퍼티는 key 와 value 쌍을 가지며 표현은 key: value
로 하게 됩니다. key 는 문자형이나 심볼형만 사용할 수 있으며, value 는 원시형 값과 객체등 거의 모든 자료형이 허용됩니다.객체 리터럴 ES6 확장
let x = 1, y = 2; const obj = { x, y }; console.log(obj); // {x: 1, y: 2}
// ES6 const prefix = 'prop'; let i = 0; // 객체 리터럴 내부에서 계산된 프로퍼티 이름으로 프로퍼티 키를 동적 생성 const obj = { [`${prefix}-${++i}`]: i, [`${prefix}-${++i}`]: i, [`${prefix}-${++i}`]: i, }; console.log(obj); // {prop-1: 1, prop-2: 2, prop-3: 3}
const obj = { name: 'Lee', sayHi() { console.log('Hi! ' + this.name); } }; obj.sayHi(); // Hi! Lee
const obj = { name: 'Lee', sayHi() { console.log('Hi! ' + this.name); } }; const obj2 = { ...obj, name: 'Hong' } obj.sayHi(); // Hi! Hong
- V8 엔진은 자바스크립트 객체 리터럴을 어떻게 해석하고 내부적으로 저장할까요?
- 클래스 기반 객체지향언어에서의 객체 선언 및 메모리 관리
- 자바스크립트 객체 선언 및 메모리 관리
- 히든 클래스
자바나 C++ 같은 클래스 기반 객체 지향 언어는 이미 프로퍼티와 메소드가 지정되어있어서, 메모리에 얼마나 많은 공간이 필요한지 바로 알 수 있습니다. 그래서 새 객체를 만들 때 메모리를 어떻게 확보할지에 대한 로직이 간단합니다.
하지만 자바스크립트 객체는 동적으로 생성되며, 프로퍼티가 추가 삭제 될 수 있고, 순서 또한 보장되지 않습니다. 그래서 v8 엔진은 객체 프로퍼티 key와 value 관련한 해시 테이블을 두고 접근합니다. 하지만, 이는 성능적으로 좋지 않습니다. v8 은 여기서 성능을 위한 히든 클래스라는 개념을 캐싱 매커니즘으로 사용하고 있습니다.
히든 클래스는 프로퍼티가 바뀔 때, 각각 그 객체에 대한 클래스를 만들어 놓는다고 생각하면 쉽습니다. 히든 클래스는 객체와 매핑이 되며, 이를 통해 메모리에 어떻게 올라가게 될 지 빠르게 예측할 수 있습니다. 여느 캐시가 그렇듯이 캐시가 없을 때의 첫 연산은 무겁지만, 그 이후 다시 접근 할 때는 더 빠르게 접근 할 수 있습니다. 이렇게 만들어 놓은 히든 클래스들 덕분에 선언된 프로퍼티가 비슷한 객체들은 관련 히든 클래스 덕분에 프로퍼티 접근 속도가 빨라질 수 있습니다. (이때, 히든 클래스는 프로퍼티의 value 값이 변경된다고 새로 생성 되는 것은 아닙니다.)
또한, 객체의 프로퍼티 순서가 다르면 다른 히든 클래스를 가지게 됩니다.
// 두 객체가 가지는 히든 클래스는 다릅니다. const obj1 = { a: 1, b: 2 }; const obj2 = { b: 2, a: 1 };
- 객체 프로퍼티를 동적으로 변경하는 것은 무거운 연산인 편입니다.
- 객체 리터럴로 선언 할 때, 같은 프로퍼티를 가지는 객체가 많다면, 그 프로퍼티의 순서가 중요합니다.
- 객체 리터럴로 선언 할 때, 빈 값으로 선언 했다가 변경하는 것 보다, 그 프로퍼티들을 미리 선언해주는 것이 좋습니다.
히든 클래스는 객체의 프로퍼티가 추가, 삭제 될 때 새로 생깁니다. 이 히든 클래스 생성은 오버헤드가 되기 때문에, 동적 수정 (
delete
연산이나 한 객체에서 프로퍼티를 새로 추가 하는 것)은 상대적으로 무거운 연산이 되게 됩니다. 프로퍼티가 유사한 객체들은 프로퍼티의 순서를 맞추어 선언하면 성능적으로 도움이 됩니다.
1번의 이유와 같은 이유로 객체 프로퍼티가 동적으로 변경되는 행위이기 때문입니다. 빈 객체 선언은 대부분의 경우에 성능에 좋을 일이 없겠네요.