Europe/Kyiv
Posts

JavaScript Proxy: перехоплення операцій над об'єктами

June 14, 2025
Proxy — це обгортка навколо об'єкта, яка дозволяє перехоплювати та переозначати будь-які операції над ним: читання, запис, видалення властивостей тощо. Саме на Proxy побудована система реактивності у Vue 3, а також багато інших бібліотек для валідації та спостереження за даними.
const proxy = new Proxy(target, handler);
  • target — об'єкт, який ми обгортаємо.
  • handler — об'єкт з пастками (traps), що перехоплюють операції.
const user = { name: 'Alice', age: 25 };

const proxy = new Proxy(user, {
  get(target, prop) {
    console.log(`Reading: ${prop}`);
    return prop in target ? target[prop] : 'Property not found';
  }
});

console.log(proxy.name);  // Reading: name → 'Alice'
console.log(proxy.email); // Reading: email → 'Property not found'
const user = { name: 'Alice', age: 25 };

const proxy = new Proxy(user, {
  set(target, prop, value) {
    if (prop === 'age' && typeof value !== 'number') {
      throw new TypeError('Age must be a number');
    }
    target[prop] = value;
    return true; // обов'язково повертаємо true
  }
});

proxy.age = 30;      // OK
proxy.age = 'old';   // TypeError: Age must be a number
const range = { min: 1, max: 100 };

const proxy = new Proxy(range, {
  has(target, value) {
    return value >= target.min && value <= target.max;
  }
});

console.log(50 in proxy);  // true
console.log(200 in proxy); // false
Ось спрощена версія того, як Vue 3 відстежує зміни даних:
function reactive(obj) {
  return new Proxy(obj, {
    get(target, prop) {
      console.log(`[GET] ${prop}`);
      return target[prop];
    },
    set(target, prop, value) {
      console.log(`[SET] ${prop} = ${value}`);
      target[prop] = value;
      // тут Vue викликає оновлення компонента
      return true;
    }
  });
}

const state = reactive({ count: 0 });

state.count++;        // [GET] count → [SET] count = 1
console.log(state.count); // [GET] count → 1
const user = { name: 'Alice', _password: 'secret' };

const proxy = new Proxy(user, {
  deleteProperty(target, prop) {
    if (prop.startsWith('_')) {
      throw new Error(`Cannot delete private property: ${prop}`);
    }
    delete target[prop];
    return true;
  }
});

delete proxy.name;      // OK
delete proxy._password; // Error: Cannot delete private property: _password
Proxy — це один з найпотужніших інструментів сучасного JavaScript. Він дозволяє:
  • Валідувати дані при записі.
  • Логувати доступ до властивостей.
  • Створювати реактивні об'єкти (як у Vue 3).
  • Захищати приватні властивості.
  • Будувати DSL та магічні API.
Єдиний мінус — Proxy не можна повністю поліфілити для старих браузерів, тому він вимагає середовища з підтримкою ES2015+.