Метапрограммирование: Proxy, Reflect, Symbol
Proxy
Прокси — обёртка вокруг объекта, которая «по умолчанию» перенаправляет операции на объект, но может их перехватывать. Проксировать можно любой объект, включая классы и функции.
let proxy = new Proxy(target, {
/* ловушки (traps) */
});Прокси не имеет собственных свойств или методов — он перехватывает операцию, если есть соответствующая ловушка, иначе перенаправляет её на target.
Можно перехватывать:
- чтение (
get), запись (set), удаление (deleteProperty) свойства — даже несуществующего; - вызов функции (
apply); - оператор
new(ловушкаconstruct); - и многие другие операции.
Reflect
Reflect — API, созданное как дополнение к Proxy. Для любой ловушки из Proxy есть метод в Reflect с теми же аргументами. Его используют, когда нужно перенаправить операцию на оригинальный объект.
let proxy = new Proxy(target, {
get(obj, prop, receiver) {
return Reflect.get(obj, prop, receiver); // перенаправляем на оригинал
},
});Symbol
Символ — примитивный тип данных для создания уникальных идентификаторов. Создаётся вызовом Symbol(), в который можно передать описание (имя).
const a = Symbol("id");
const b = Symbol("id");
a === b; // false — даже с одинаковым описанием это разные символыГлобальный реестр: Symbol.for(key) возвращает (или создаёт) глобальный символ с key в качестве имени. Повторные вызовы с тем же аргументом возвращают тот же символ.
Symbol.for("id") === Symbol.for("id"); // trueСимволы скрыты не на 100%: получить символьные ключи объекта можно через Object.getOwnPropertySymbols(obj) и Reflect.ownKeys(obj). Но большинство библиотек и синтаксических конструкций их не используют.
Well-Known Symbols (системные): множество «системных» символов, используемых внутри самого JavaScript (например, Symbol.iterator, Symbol.asyncIterator), которыми можно настраивать поведение объектов.