V8 Hidden Classes (Shapes)

Hidden Class (он же Shape, Map) — внутренняя структура V8, описывающая «форму» объекта: список свойств и их порядок. Объекты с одинаковой shape делят один Hidden Class — это основа Inline Cache.

Что это / Зачем

JavaScript — динамический язык. Но V8 пытается ускорить доступ к свойствам, как если бы это были поля статически типизированной структуры. Для этого:

  • При создании объекта присваивается Hidden Class
  • Hidden Class знает offset каждого свойства внутри объекта
  • Доступ obj.x → не "поиск в хэш-таблице", а "прочитай по offset X"
  • Объекты с одинаковыми свойствами в одинаковом порядке имеют одну shape

Пример transition'ов

const a = {};         // Hidden Class C0 (пустой)
a.x = 1;              // C0 → C1 (есть x)
a.y = 2;              // C1 → C2 (есть x, y)

const b = {};         // C0
b.x = 1;              // C1 — та же что у a
b.y = 2;              // C2 — та же что у a
// a и b разделяют C2 → одинаковая shape

const c = {};
c.y = 2;              // C0 → C3 (есть y)
c.x = 1;              // C3 → C4 (есть y, x)
// c имеет ДРУГОЙ Hidden Class — другой порядок!

Правила сохранения shape

  1. Добавляйте поля в одном порядке в конструкторе:
// Хорошо
class Point {
  constructor(x, y) {
    this.x = x;  // всегда первое
    this.y = y;  // всегда второе
  }
}

// Плохо — разные shapes
function Bad(x, y) {
  if (random) { this.x = x; this.y = y; }
  else          { this.y = y; this.x = x; }
}
  1. Не используйте delete — превращает объект в dictionary mode (медленная hashmap):
const obj = { x: 1, y: 2 };
delete obj.x;  // ← shape сломан, объект в slow mode
  1. Не добавляйте поля после создания:
const obj = { x: 1 };  // shape: {x}
// ... 1000 строк кода ...
obj.y = 2;  // shape transition в горячем месте — деопт
  1. Инициализируйте все поля сразу в null если значения нет:
class User {
  constructor {
    this.name = null;
    this.email = null;
    this.age = null;
  }
}

Связь с Inline Cache

Когда V8 видит function get(o) { return o.x }:

  • Первый вызов: записывает в IC slot пару (Hidden Class, offset для x)
  • Следующие вызовы с тем же Hidden Class: используют закешированный offset (monomorphic)
  • Несколько Hidden Classes: polymorphic (медленнее)
  • Много (>4): megamorphic — IC отключается, поиск через hashmap

Подводные камни

  • Object.create(null) создаёт объект без прототипа — отдельный shape
  • Spread {...obj} создаёт новый объект с новым Hidden Class
  • Symbol-ключи учитываются в shape, но в отдельной структуре
  • Object.freeze создаёт frozen shape — read-only

🎓 Источники

  • ⚡ [Производительность JS Обьекты в V8] · AsForJS · 2025-02-07 · YouTube
    • Тезисы: V8 строит дерево hidden classes через transitions. Каждый объект — точка в этом дереве. Одинаковая shape = одна точка
  • ⚡ [Производительность V8 объектов в примерах] · AsForJS · 2025-02-11 · YouTube
    • Тезисы: delete ломает shape — переход в dictionary mode. null-инициализация полей сохраняет shape
  • 🎓 [Мономорфный и полиморфный код, инлайн-кэш, скрытые классы] · 2019-10-29 · YouTube
    • Тезисы: монолитный код с одинаковыми shapes = быстрый. Полиморфизм/мегаморфизм = медленный. Это применимо ко ВСЕМ объектам, не только из class

См. также