|
Reference Record (запись ссылки) — это внутренний тип данных в спецификации ECMAScript, который используется для объяснения поведения таких операторов, как delete, typeof, операторов присваивания, ключевого слова super и других языковых конструкций. Например, левый операнд присваивания должен выдавать Reference Record.
Простыми словами, Reference Record — это промежуточная структура, которая описывает "к чему мы обращаемся" и "как к этому обращаться" до того, как значение будет фактически прочитано или записано. Она связывает имя (или выражение) с местом, где хранится значение.
[Поля (Fields) Reference Record]
Согласно спецификации, Reference Record состоит из четырёх полей:
| Поле |
Тип значения |
Описание |
| [[Base]] |
ECMAScript-значение, Environment Record или `~unresolvable~` |
Значение или запись окружения, которая содержит привязку. `~unresolvable~` означает, что привязка не может быть разрешена. |
| [[ReferencedName]] |
Строка, Символ или Private Name |
Имя привязки. Всегда строка, если [[Base]] — это Environment Record. Для свойств может быть ещё не разрешённым ключом. |
| [[Strict]] |
Boolean |
true, если Reference Record возник в строгом режиме, иначе false. |
| [[ThisValue]] |
ECMAScript-значение или `~empty~` |
Если не `~empty~`, то Reference Record представляет привязку к свойству, выраженную через ключевое слово super. В этом случае [[Base]] никогда не будет Environment Record, а [[ThisValue]] хранит значение this на момент создания Reference Record. |
[Классификация ссылок]
Спецификация определяет несколько абстрактных операций для проверки типа Reference Record:
• IsUnresolvableReference: [[Base]] равен `~unresolvable~`. • IsPropertyReference: [[Base]] не является ни `~unresolvable~`, ни Environment Record. Это ссылка на свойство объекта. • IsSuperReference: [[ThisValue]] не равен `~empty~`. Это ссылка, созданная с использованием super. • IsPrivateReference: [[ReferencedName]] является Private Name. Это ссылка на приватное поле класса.
[Как это работает: GetValue и PutValue]
Основное назначение Reference Record — передаваться в абстрактные операции `GetValue` (для чтения) и `PutValue` (для записи), которые определяют, как именно получить или изменить значение.
Логика `GetValue(V)`:
1. Если `V` — не Reference Record, то вернуть `V` как есть (это просто значение).
2. Если `V` — unresolvable reference, то выбросить `ReferenceError`.
3. Если это ссылка на свойство (IsPropertyReference), то получить базовый объект и вызвать его внутренний метод [[Get]], передав [[ReferencedName]] и правильное this (которое для super будет [[ThisValue]]).
4. Если это ссылка на окружение (Identifier), то вызвать `GetBindingValue` у соответствующей Environment Record.
Логика `PutValue(V, W)`: аналогична, но с записью: unresolvable reference в строгом режиме выбрасывает `ReferenceError`, ссылка на свойство вызывает [[Set]], а ссылка на окружение — SetMutableBinding.
[Зачем это нужно?]
Reference Record — это спецификационный приём, а не доступная программисту конструкция. Он позволяет точно описать разницу между семантикой работы с переменными (хранящимися в Environment Record) и свойствами объектов. Без этой абстракции было бы сложно объяснить, почему `delete obj.prop` и `delete varName` работают по-разному, или почему `super.method()` корректно находит метод в прототипе.
Важно отметить, что реализация движками JavaScript не обязана создавать объект Reference Record для каждого обращения. Спецификация прямо указывает, что объект, который может быть создан в ходе `GetValue`/`PutValue`, недоступен за пределами этих операций, и реализация может избежать его фактического создания. |