Delegation Chain (цепочка делегирования)

Delegation Chain — один фундаментальный принцип из computer science, объясняющий сразу пять механизмов JavaScript: prototype chain, разрешение идентификаторов (scope), окружения, поведение генераторов и работу Object.

«Этот термин я сам не придумал — он используется в computer science. В спецификации ECMAScript его нет, но он удобен, чтобы не смешивать абстракцию и реализацию» (автор, Part 3).

Два правила принципа

  1. Знаю ответ — даю ответ.
  2. Не знаю — есть ли связь? Если есть единственная связь, делегирую запрос дальше, жду ответа, возвращаю спросившему.

Два жёстких ограничения

  • Связь только одна. Сущность может делегировать строго одному следующему звену. К ней самой могут обращаться многие — но она отвечает или передаёт ровно одному.
  • Нельзя создавать кольца. Цепочка строго однонаправленная. Кольцо → бесконечный цикл (вспомним Object.setPrototypeOf(a, b) где b → a — TypeError "Cyclic proto value").

Аналогия: справочные с одним телефоном

Бабуля в справочной ищет в своей амбарной книге. Не нашла — снимает трубку, может набрать только один номер. На том конце — другая бабуля, у неё своя книга. Не нашла — звонит дальше. У последней второго телефона нет: ответ undefined.

Чем отличается от Linked List

Linked list звенья одного типа, одна структура
Delegation chain звенья могут различаться, каждое обрабатывает запрос по-своему

Гарантируется лишь наличие одной связи. Делегируется работа, а не готовый ответ — каждое звено выполняет собственный поиск.

Где работает в JavaScript

  1. Prototype chain — поиск свойства идёт obj → __proto__ → __proto__ → ... → Object.prototype → null.
  2. Resolve identifier (разрешение идентификаторов) — поиск переменной в LexicalEnvironment по такой же цепочке.
  3. Variable Environment / Lexical Environment — само устройство scope строится цепочкой.
  4. Generators / iteratorsnext делегирует во вложенный итератор через yield*.
  5. Object internal methods[[Get]], [[Set]], [[HasProperty]] идут по [[Prototype Pattern]].

Минимальный пример

const root = { color: 'red' };
const middle = Object.create(root); // middle → root
middle.size = 'm';
const leaf = Object.create(middle); // leaf → middle → root

leaf.color; // 'red' — звено leaf не знает, делегирует middle, потом root
leaf.size;  // 'm' — middle ответил
leaf.shape; // undefined — последнее звено не имеет связи, ответа нет

Кольцо запрещено

const a = {};
const b = {};
Object.setPrototypeOf(a, b);
Object.setPrototypeOf(b, a); // TypeError: Cyclic __proto__ value

Длина цепочки = время поиска

«Уход вглубь — это лишнее время. Если свойство в конце цепочки, поиск долгий. При промахе движок проходит до самого null», SzaXTW2qcJE.

Поэтому глубокие иерархии наследования замедляют чтение методов (5+ уровней — антипаттерн).

Сравнение с таблицей маршрутизации

Слушатель автора предложил аналогию с роутером: но routing-таблица ближе к деревьям и графам (много маршрутов). Delegation chain — это один дефолтный роутер. Совпадает только если у роутера единственный маршрут.

Источники

Связанные темы