Проксі у JavaScript

6 хв. читання
27 листопада 2017

Що таке проксі?

Перш за все необхідно визначитися, що таке проксі? Зазирнемо до Оксфордського словника.

Визначення проксі англійською мовою: повноваження представляти когось іншого.

У цьому контексті, якщо ви звертаєтесь до проксі іншої особи, то можна вважати, що ви напряму спілкуєтесь з особою.

Натомість у JavaScript замість осіб виступають об'єкти.

Що таке проксі у JavaScript?

Визначення терміну від MDN,

Проксі – об'єкт, який використовується для визначення нестандартної поведінки базових операцій (пошук властивостей, перерахування, виклик функцій, тощо).

Не дуже зрозуміло, спробуємо розглянути на прикладі.

Уявіть собі директора і його асистента.

Зазвичай асистент займається поштою директора. Перш ніж передавати лист директору, він може виправляти помилки, додавати посилання до зазначених в листі речей, тощо.

У цьому випадку асистент виступає у ролі проксі, він перехоплює дані адресовані директору (цілі), трансформує їх у більш зрозумілий для директора (цілі) формат, і потім передає їх безпосередньо директору.

Або ж, асистент може зберігати час директора. Коли хтось хоче зустрітися з директором (тобто потребує його часу), вони спершу мають зв'язатися з асистентом і він з огляду на певні умови визначить дату зустрічі, або якщо має таке право, відхилить зустріч.

У цьому випадку, якщо хтось намагається зустрітися з директором (ціллю), то асистент (проксі) перехоплює його запит і залежно від умов (хто питає, або навіщо) може надати доступ до директора, або може відмовити, або ж дати відповідь самостійно, не турбуючи директора (ціль).

Тепер переходимо від теорії до практики.

Код проксі у JavaScript

Приблизно так виглядає базовий проксі у JS:

const target = {};
const handler = {};
const proxy = new Proxy(target, handler);
  • target – цільовий об'єкт, для якого буде працювати проксі (директор з попереднього прикладу);
  • handler – об'єкт, який містить властивості проксі. Іншими словами, це умови, за яких проксі має перехоплювати дані адресовані цільовому об'єкту;
  • proxy – фактично, сам об'єкт Proxy(target, handler).

Тут проксі не робить нічого, оскільки ми не визначили жодних опцій за яких він працюватиме, він є прохідним об'єктом. Тож ви можете вільно працювати з цільовим об'єктом через проксі без перешкод.

Пастки (Traps)

Пастками називають властивості проксі.

Коли ви визначаєте пастку, ви повідомляєте проксі-серверу, коли необхідно виконувати певну дію, якщо пастку не визначено, то проксі за замовчуванням буде пересилати дані до цільового об'єкта.

Частіше за все ви будете використовувати пастки get i set, які будуть отримувати й встановлювати інші пастки.

Get пастка

Пастка Get викликається, якщо ви намагаєтеся отримати доступ до властивості target за допомогою проксі-сервера, наприклад:

const target = {};
const handler = {
  get: (target, property) => {
    console.log(`Accessing property '${property}'`);
    return target[property];
  }
};
const proxy = new Proxy(target, handler);
proxy.a;
// виводить "Accessing property 'a'" до консолі

Get – метод, який приймає ціль(цільовий об'єкт) і властивості(умови, які ми хочемо отримати).

Якщо ви намагаєтесь отримати властивість «а» через проксі, то спершу буде виведено до консолі дію, яку ви виконуєте і повернено значення властивості.

Set пастка

Set пастка викликається коли ви намагаєтесь задати нове значення полю target через проксі.

const target = {};
const handler = {
  set: (target, property, value) => {
    console.log(`Updating property '${property}' with value
      '${value}'`);
    target[property] = value;
    return true;
  }
};
const proxy = new Proxy(target, handler);
proxy.a = 'NewValue';
// logs "Updating property 'a' with value 'NewValue'" to the console

Set – метод, який приймає три параметри:

  • target – цільовий об'єкт;
  • propery – властивість, яку ми намагаємось оновити;
  • value – значення яке ми надаємо цій властивості.

У цьому прикладі ми оновлюємо властивість а об'єкту target через проксі, ця операція перехоплюється пасткою setxy, яка реєструє властивість, яку потрібно оновити, та її значення.

Зверніть увагу, пастка set повертає логічне значення. true, якщо присвоювання виконано або false, яке викликає TypeError, якщо ви знаходитесь у суворому режимі.

Використання проксі для уникнення доступу до невизначених властивостей (undefined)

Досі ми не використовували проксі для чого-небудь особливого, корисного, давайте це виправимо.

Напишемо код, який допоможе уникнути випадкового доступу до властивостей не об'єктів.

const target = {};
const handler = {
  get: (target, property) => {
    target[property] = (property in target) ? target[property] : {};
    if (typeof target[property] === 'object') {
      return new Proxy(target[property], handler);
    }
    return target[property];
  }
}
const proxy = new Proxy(target, handler);
proxy.x.y.z;

Цікава частина цього прикладу – get пастка.

Вона перехоплює спробу отримати властивість і перевіряє, чи існує властивість у цільовому об'єкті. Якщо так, вона задає значення властивості для самої себе (тобто нічого не виконує), якщо ні, вона ініціалізує цю властивість порожнім об'єктом.

Потім пастка перевіряє чи є властивість об'єктом, і чи повертає він новий проксі з таким самим обробником, але тепер об'єктом є target [property], оскільки проксі не розповсюджуються на інші об'єкти всередині цільового об'єкта.

Останнє значення, що повертається – властивість target, якщо вона не є об'єктом.

Тепер коли ми намагаємося отримати доступ до цільового об'єкта x.y.z через проксі, він не повертає Cannot read property 'y' of undefined, а створює об'єкти.

Будьте обачні, цей приклад було створено на швидку руку, тож його не перевірено як слід. Для серйозного використання необхідно вкласти в нього більше зусиль.

Більше прикладів

Ви можете знайти більше цікавих прикладів проксі на MDN. Мені подобається приклад, що повертає стандартне значення, якщо властивість, до якої намагалися дістатися, не є ціллю, і той, що модифікує DOM, використовуючи proxy set trap.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.6K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація