JS Advanced

Proxy и Reflect

Понять, как Proxy перехватывает операции над объектами (get, set, has, apply) и как Reflect предоставляет стандартные операции.

Продвинутый (Advanced)

Кратко

Proxy оборачивает объект и перехватывает операции: get (чтение), set (запись), has (проверка in), apply (вызов функции). Reflect предоставляет стандартные операции JavaScript, зеркальные traps. Proxy + Reflect = метапрограммирование: валидация, логирование, реактивность.


Подробно

Создание Proxy: const handler = { get(target, prop) { console.log(Чтение: ${prop}); return Reflect.get(target, prop); }, set(target, prop, value) { console.log(Запись: ${prop} = ${value}); return Reflect.set(target, prop, value); } };

const obj = { name: 'Анна' }; const proxy = new Proxy(obj, handler);

proxy.name; // Чтение: name → 'Анна' proxy.age = 25; // Запись: age = 25

Типичные traps:

  • get(target, prop, receiver) — чтение свойства
  • set(target, prop, value, receiver) — запись свойства
  • has(target, prop) — оператор in
  • apply(target, thisArg, args) — вызов функции
  • construct(target, args) — оператор new

Reflect — зеркальный API: // Без Reflect (рекурсивная ловушка) get(target, prop) { return target[prop]; }

// С Reflect (рекурсия корректна) get(target, prop, receiver) { return Reflect.get(target, prop, receiver); }

Практический пример — валидация: const validator = { set(target, prop, value) { if (prop === 'age' && typeof value !== 'number') { throw new TypeError('Age must be a number'); } return Reflect.set(target, prop, value); } };

const user = new Proxy({}, validator); user.age = 25; // OK // user.age = 'двадцать пять'; // TypeError


Ментальная модель

Proxy — как охранник у двери объекта. Когда кто-то пытается прочитать свойство (get) — охранник проверяет и решает, пропустить или нет. Reflect — как инструкция для охранника: «Сделай то, что обычно делает объект, но через меня.»


Примеры

**Самый простой:**

javascript
const handler = {
  get(target, prop) {
    return prop in target ? target[prop] : 'не найдено';
  }
};

const obj = new Proxy({ a: 1 }, handler);
console.log(obj.a);  // 1
console.log(obj.b);  // 'не найдено'

Простейший Proxy: обработка отсутствующих свойств.

**Простой:**

javascript
// Реактивный объект
function reactive(obj, onChange) {
  return new Proxy(obj, {
    set(target, prop, value) {
      const oldValue = target[prop];
      const result = Reflect.set(target, prop, value);
      if (oldValue !== value) {
        onChange(prop, value, oldValue);
      }
      return result;
    }
  });
}

const state = reactive({ count: 0 }, (prop, newVal) => {
  console.log(`${prop} изменился на ${newVal}`);
});

state.count = 1; // 'count изменился на 1'
state.count = 5; // 'count изменился на 5'

Реактивность через Proxy — основа Vue 3 и аналогичных библиотек.

**Реальный пример:**

javascript
// Отладка: логирование всех операций
function debugProxy(obj, name) {
  return new Proxy(obj, {
    get(target, prop) {
      console.log(`[${name}] GET ${String(prop)}`);
      return Reflect.get(target, prop);
    },
    set(target, prop, value) {
      console.log(`[${name}] SET ${String(prop)} = ${value}`);
      return Reflect.set(target, prop, value);
    },
    has(target, prop) {
      console.log(`[${name}] HAS ${String(prop)}`);
      return Reflect.has(target, prop);
    }
  });
}

const user = debugProxy({ name: 'Анна' }, 'User');
user.name; // [User] GET name
user.age = 25; // [User] SET age = 25

Proxy для отладки: логирование всех операций над объектом.


Частые ошибки

**Неправильно:** Создавать Proxy без Reflect

**Почему:** Без Reflect вызов методов оригинального объекта (target[prop]) может нарушить рекурсию.

**Правильно:** Используйте Reflect.get/set для корректной рекурсии.

**Неправильно:** Думать, что Proxy не влияет на производительность

**Почему:** Proxy добавляет перехват на каждую операцию — это медленнее прямого доступа.

**Правильно:** Proxy = метапрограммирование. Используйте только когда нужно.


Важно запомнить

  • Proxy перехватывает операции над объектом
  • Reflect предоставляет стандартные операции
  • Типичные traps: get, set, has, apply, construct
  • Proxy замедляет доступ к свойствам
  • Proxy — основа реактивности (Vue 3, MobX)

Связь

Назад: Вы знаете объекты (J11) и дескрипторы свойств (JV15). Proxy перехватывает операции над объектами.

Вперёд: Следующий урок (JV8) — генераторы — функции, которые могут приостанавливаться и возобновляться.


Читайте дальше

Материалы курса JS Advanced — PROlab Academy.