Object Representation
Khi một đối tượng trong JS được tạo, V8 sẽ tạo ra một con trỏ có giá trị là vùng nhớ của đối tượng JSObject
trong C++.
Bên trong một JSObject
sẽ bao gồm những thành phần sau:
- Map: con trỏ của hidden class của đối tượng.
- Properties: con trỏ của đối tượng chứa các thuộc tính được đặt tên (named properties).
- Elements: con trỏ của đối tượng chứa các thuộc tính được đánh chỉ số (indexed properties).
- In-object properties: các con trỏ của các thuộc tính được lưu bên trong vùng nhớ của object.
Minh họa:
In-Object Properties
Là các thuộc tính được lưu trữ trong vùng nhớ của object.
Các thuộc tính được khai báo trong quá trình khởi tạo object (chẳng hạn như thuộc tính a
trong let o = {a:1}
) đều được lưu trữ trong vùng nhớ của object. Trong khi đó, các thuộc tính được thêm vào sau quá trình khởi tạo object có thể không được lưu trong vùng nhớ của object.
Xét ví dụ sau:
const obj = {};
obj.a = 1;
% DebugPrint(obj);
Info
%DebugPrint
là một native function của V8 giúp in ra thông tin của object.
Output khi chạy với D8 Shell:
d8> %DebugPrint(obj)
DebugPrint: 0x134a001cc789: [JS_OBJECT_TYPE]
- map: 0x134a000db555 <Map[16](HOLEY_ELEMENTS)> [FastProperties]
- prototype: 0x134a000c4b79 <Object map = 0x134a000c41b5>
- elements: 0x134a00000219 <FixedArray[0]> [HOLEY_ELEMENTS]
- properties: 0x134a00000219 <FixedArray[0]>
- All own properties (excluding elements): {
0x134a00002a49: [String] in ReadOnlySpace: #a: 1 (const data field 0), location: in-object <----
}
...
Trong output trên, ta thấy rằng thuộc tính a
có location
là in-object
.
Số lượng các thuộc tính in-object sẽ có giới hạn tùy thuộc vào kích thước ban đầu của thuộc tính và sẽ được lưu ở trong vùng nhớ của con trỏ properties
nếu có nhiều thuộc tính được thêm vào.
Ví dụ:
const obj = {};
obj.a = 1;
obj.b = 2;
obj.c = 3;
obj.d = 4;
obj.e = 5;
% DebugPrint(obj);
Output:
d8> %DebugPrint(obj)
DebugPrint: 0x327001cc785: [JS_OBJECT_TYPE]
- map: 0x0327000dce45 <Map[28](HOLEY_ELEMENTS)> [FastProperties]
- prototype: 0x0327000c4b79 <Object map = 0x327000c41b5>
- elements: 0x032700000219 <FixedArray[0]> [HOLEY_ELEMENTS]
- properties: 0x0327001ce8e9 <PropertyArray[3]>
- All own properties (excluding elements): {
0x32700002a49: [String] in ReadOnlySpace: #a: 1 (const data field 0), location: in-object
0x32700002a59: [String] in ReadOnlySpace: #b: 2 (const data field 1), location: in-object
0x32700002a69: [String] in ReadOnlySpace: #c: 3 (const data field 2), location: in-object
0x32700002a79: [String] in ReadOnlySpace: #d: 4 (const data field 3), location: in-object
0x32700002a89: [String] in ReadOnlySpace: #e: 5 (const data field 4), location: properties[0]
}
...
Trong output trên, ta thấy thuộc tính thứ 5 được thêm vào không còn nằm trong cùng vùng nhớ với object nữa mà sẽ được lưu ở trong vùng nhớ của con trỏ properties
.
Properties
Con trỏ properties
của một object sẽ trỏ đến một đối tượng và bên trong đối tượng đó sẽ có một mảng lưu trữ giá trị của các named property. Để truy xuất một named property ở trong mảng của properties
(mà ta gọi là backing store của properties
), V8 sẽ sử dụng instance descriptor có trong hidden class.
Việc truy xuất giá trị của thuộc tínha
diễn ra như sau:
- Truy cập đến map của object.
- Từ map, tìm instance descriptors.
- Truy xuất index của
a
ở trong instance descriptors. - Sử dụng index có được để truy xuất giá trị của
a
ở trong backing store củaproperties
.
Trong trường hợp việc thêm hoặc xóa thuộc tính ra khỏi object diễn ra quá thường xuyên, V8 sẽ chuyển cấu trúc dữ liệu lưu giá trị của các named property từ mảng sang dictionary. Khi đó, dictionary sẽ chứa tất cả các metadata của các thuộc tính và instance descriptor ở trong map của object sẽ là rỗng:
Ta gọi đối tượng được trỏ đến bởi properties
mà lưu các thuộc tính ở trong mảng là FastProperties còn đối tượng được trỏ đến bởi properties
mà lưu các thuộc tính trong dictionary là SlowProperties.
Elements
Đối với các indexed property, chúng cũng được lưu trong backing store của đối tượng mà elements
trỏ đến và sẽ được truy xuất thông qua chỉ số.
Backing store của elements
có nhiều loại tùy thuộc vào kiểu dữ liệu của các phần tử bên trong mảng. Việc xác định loại backing store (hay còn gọi là element kind) giúp V8 tối ưu việc sử dụng các thao tác trên mảng dựa trên kiểu dữ liệu của các phần tử bên trong nó.
Có 2 element kind chính là PACKED
và HOLEY
. Nếu element kind là PACKED
, các phần tử bên trong mảng sẽ nằm sát nhau. Ngược lại với nó là HOLEY
, các phần tử bên trong mảng nằm thưa với nhau và xảy ra khi chúng ta xóa hoặc không khai báo phần tử.
PACKED
và HOLEY
lại được chia thành 3 loại dành cho các số nguyên nhỏ (small integer - SMI), số chấm động chính xác kép (double) và các giá trị tổng quát:
Các mảng có element kind cụ thể có thể được chuyển thành mảng có element kind tổng quát nhưng không có chiều ngược lại.
Tương tự với properties
, backing store của elements
cũng có thể ở dạng dictionary. Điều này xảy ra khi mảng được khai báo với kích thước rất lớn nhưng chỉ có một vài phần tử.
Related
list
from outgoing([[Object Representation]])
sort file.ctime asc