자바스크립트 객체는 다른가?

jaehan·2023년 5월 21일
0

JavaScript

목록 보기
31/33
post-thumbnail

자바스크립트의 객체

자바스크립트는 동적 타이핑 언어이다.
또한 자바스크립트는 원시값을 제외하면 모두 객체이다.

이 자바스크립트 객체의 프로퍼티 또한 동적으로 정해진다.

이렇게 되면 안좋은 점은 프로퍼티가 동적으로 계속 바뀌고 추가될 수 있기 때문에 이 프로퍼티의 값을 찾기 위해서 미리 정해놓을 수 없고 할떄 마다 계속 찾아야 한다는 큰 단점이있다.

이를 동적탐색이라고 하는데 이는 프로퍼티를 읽어들일때 비용이 발생하게 된다.

V8

이를 해결하기 위해 V8은 히든 클래스라는 것을 활용하여 동적 탐색을 회피한다.

히든클래스가 뭔지는 그림과 실제 크롬 브라우저를 활용해서 보면 이해가 된다.

let a = {}

a.x = 1;
a.y = 2;

위코드를 실행시키면 아래와 같이 나오게 된다.

우선 처음에 빈객체를 만들게 되면 c0이라는 히든 클래스를 만든다.

다음으로 a.x를 하게 되면 c1 히든 클래스를 만들고 c0을 상속받는다.
그리고 offset0에 x를 할당한다.
📌 이때 c0에는 x를 추가하면 c1을 참조하는 것이다라는 정보가 저장된다고 한다.

다음으로 a.y를 하게 되면 c2 히든 클래스를 만들고 c1을 상속받는다.
그리고 offset1에 y를 할당한다.
📌 이때에는 c1에는 y를 추가하면 c2을 참조하는 것이다라는 정보가 저장된다.

이렇게 하는 이유는 프로퍼티를 동적으로 생성할때 마다 새로 만드는 것이 아닌 x를 추가하면 c1을 재사용 하고 y를 추가하면 c2를 재사용 하면 되기 때문에 효율이 좋아지게 되는 것이다.

이걸 크롬 브라우저에서 간단하게 나마 확인할 수 있다.

function Person(name) {
 this.name = name;
}

let a = new Person("kim");
let b = new Person("lee");

위 코드를 콘솔창에 입력하고 memory탭에 들어가서 스냅샷을 찍어보면

위와 같은 결과가 나오는데 map 부분을 보면 똑같은 값을 참조하고 있는걸 볼 수 있다.

function Person(name) {
 this.name = name;
}

let a = new Person("kim");
let b = new Person("lee");
a.job = 'student';

a에 job 프로퍼티를 추가해보고 확인해 보면 아래와 같은 결과가 나온다.

위의 결과에서 첫번째 person의 map과
두번째 person의 map안에 transition의 값이 같은걸 볼 수 있다.

이건 뭐를 뜻하냐면
a와 b는 같은 히든 클래스를 참조하고 있었는데 a는 프로퍼티를 하나 더 생성했기 때문에

참조하고 있던 히든클래스가 새로운 히든클래스를 참조하게 되었다.

그리고 기존 히든클래스에는 새로운 히든 클래스를 참조했다는 값이 저장되는 것이고

이를 b가 참조하고 있기 때문에 b에서 같은 값을 찾을 수 있는 것이다.


이를 통해 v8은 동적 탐색을 피하고 속도를 최적화 시킨것이라고 배우게 되었다.

배열

자바스크립트에서 배열은 기존의 연속된 메모리를 가진 배열과는 다르게 객체로 구성되어있다.

자바스크립트 객체는 위처럼 구성되어있는데 배열은 이중에서 indexed properties를 가지는 객체라고 생각하면 된다.

또한 위 그림처럼 packed, holey, smi, double 이렇게 나눠지는데
Packed는 배열처럼 0부터 n까지 꽉채워진 배열을 의미하고

Smi는 small integers element, Double은 부동 소수점을 가지는 실수이다.

따라서 가장 위에있는 값 즉 packed_smi로 배열을 관리하는게 퍼포먼스 측면으로 유리하고
오른쪽 아래로는 변할 수 있지만 왼쪽 위로는 다시 돌아올 수 없다.

예시를 보면

let a = [1]; // [1] -> packed_smi
a[2] = 3.3; // [1, empty, 3.3] -> holey_double
a[1] = 2.2; // [1, 2,2, 3.3] -> holey_double

이처럼 기존에 생성한 배열은 packed_smi였지만 1번째 인덱스를 건너뛰는 순간 holey_double로 되어서 퍼포먼스가 떨어지게 되고 empty를 바꾸더라도 다시 돌아가지 못한다.

그렇기 때문에 처음 배열을 만들때 []로 초기화 시키고 순서대로 만드는것이 가장 좋고 Array로 크기를 정하게 되면 empty가 들어가 버려서 바로 holey가 되기 때문에 효율이 좋지 않다.

총 정리

정리해보자면 자바스크립트는 동적타이핑 언어이기 때문에 객체를 생성할 때 다른 정적 타이핑 언어와 다르게 해시 테이블을 사용하지 않는다.

그 이유는 동적으로 변하기 때문에 동적 탐색을 해야 하고 동적탐색을 할때는 해시 테이블이 느리기 때문이다.

따라서 히든클래스를 사용해서 이를 해결했다.

또한 배열도 객체인데 배열처럼 0부터 n까지의 프로퍼티를 가지는 객체를 가장 최적화된 배열이라 하고 기존 객체보다 퍼포먼스가 좋다.

그러나 배열의 값으로 empty가 들어가게 되면 퍼포먼스가 떨어지게 되기 때문에 최대한 순서대로 배열의 값을 할당하는게 좋다.

참고: https://engineering.linecorp.com/ko/blog/v8-hidden-class
https://ui.toast.com/weekly-pick/ko_20210909
https://velog.io/@wongue_shin/JS%EC%9D%98-%EA%B0%9D%EC%B2%B4%EB%8A%94-hash-table%EC%9D%B4-%EC%95%84%EB%8B%99%EB%8B%88%EB%8B%A4

0개의 댓글