Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке пастки (traps)?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Пастки (traps)** - це методи в об'єкті `Proxy`, які "перехоплюють" стандартні операції з об'єктом (читання, запис, видалення властивостей, виклик функції, оператор `in` тощо) і дозволяють тобі перевизначити їхню поведінку. Простіше кажучи - пастки дають тобі можливість втрутитися в роботу JavaScript і змінити те, як об'єкт себе поводить. **Ключове:** пастки визначаються в другому аргументі `Proxy` - так званому "обробнику" (handler).Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Пастки (traps)** - це **методи в об'єкті** `Proxy`, які **"перехоплюють" стандартні операції** з об'єктом (читання, запис, видалення властивостей, виклик функції, оператор `in` тощо) і дозволяють тобі **перевизначити їхню поведінку**. Простіше кажучи - пастки дають тобі **можливість втрутитися в роботу JavaScript** і змінити те, як об'єкт себе поводить. --- ## Коротко Пастки - це функції, які визначаються в **другому аргументі** `Proxy` - у так званому **"обробнику" (handler)**: ```javascript const proxy = new Proxy(target, handler); ``` | Параметр | Опис | |---|---| | `target` | вихідний об'єкт (реальна "ціль") | | `handler` | об'єкт з "пастками" (методами, що перехоплюють дії) | --- ## Приклад - найпростіша пастка `get` ```javascript const user = { name: 'Tim' }; const proxy = new Proxy(user, { get(target, property) { console.log(`Читаємо властивість "${property}"`); return target[property]; } }); console.log(proxy.name); // → Лог: Читаємо властивість "name" // → Вивід: Tim ``` Тут пастка `get` **перехоплює звернення до властивості**, і ти можеш зробити що завгодно перед поверненням значення (лог, перевірку, валідацію, підміну тощо). --- ## Всі основні пастки | Пастка | Що перехоплює | Аналог | |---|---|---| | `get(target, prop, receiver)` | Читання властивості (`obj.prop`) | `obj[prop]` | | `set(target, prop, value, receiver)` | Запис властивості (`obj.prop = value`) | `obj[prop] = value` | | `has(target, prop)` | Перевірку `prop in obj` | `in` | | `deleteProperty(target, prop)` | Видалення (`delete obj[prop]`) | `delete` | | `ownKeys(target)` | Отримання списку ключів (`Object.keys`, `for...in`) | `Object.keys(obj)` | | `getOwnPropertyDescriptor(target, prop)` | Запит дескриптора властивості | `Object.getOwnPropertyDescriptor()` | | `defineProperty(target, prop, descriptor)` | Визначення нової властивості | `Object.defineProperty()` | | `getPrototypeOf(target)` | Отримання прототипу | `Object.getPrototypeOf()` | | `setPrototypeOf(target, proto)` | Зміну прототипу | `Object.setPrototypeOf()` | | `isExtensible(target)` | Перевірку розширюваності | `Object.isExtensible()` | | `preventExtensions(target)` | Заборону додавання нових властивостей | `Object.preventExtensions()` | | `apply(target, thisArg, args)` | Виклик функції | `func()` | | `construct(target, args, newTarget)` | Виклик з `new` | `new func()` | --- ## Приклади популярних пасток ### 1. `set` - контроль запису ```javascript const user = { name: 'Tim' }; const proxy = new Proxy(user, { set(target, prop, value) { if (prop === 'age' && typeof value !== 'number') { throw new TypeError('Вік має бути числом!'); } target[prop] = value; return true; // обов'язково повернути true } }); proxy.age = 25; // ok proxy.age = 'twenty'; // TypeError ``` --- ### 2. `has` - підміна оператора `in` ```javascript const secret = { password: '1234' }; const proxy = new Proxy(secret, { has(target, key) { if (key === 'password') return false; return key in target; } }); console.log('password' in proxy); // false ``` Так можна "приховувати" чутливі поля. --- ### 3. `ownKeys` - приховування властивостей при обході ```javascript const user = { name: 'Tim', password: '12345' }; const proxy = new Proxy(user, { ownKeys(target) { return Object.keys(target).filter(k => k !== 'password'); } }); console.log(Object.keys(proxy)); // ["name"] ``` --- ### 4. `apply` - перехоплення виклику функції ```javascript function sum(a, b) { return a + b; } const proxy = new Proxy(sum, { apply(target, thisArg, args) { console.log(`Виклик з аргументами: ${args}`); return Reflect.apply(target, thisArg, args); } }); console.log(proxy(2, 3)); // "Виклик з аргументами: 2,3" → 5 ``` Пастка `apply` працює тільки для **функцій**. --- ### 5. `construct` - перехоплення виклику з `new` ```javascript function User(name) { this.name = name; } const proxy = new Proxy(User, { construct(target, args) { console.log('Створюємо нового користувача...'); return new target(...args); } }); const tim = new proxy('Tim'); // → "Створюємо нового користувача..." ``` --- ## Як "пробрасувати" стандартну поведінку Щоб не ламати нативну поведінку, зазвичай пастки використовують `Reflect` усередині - він виконує "реальну" операцію під капотом. ```javascript const proxy = new Proxy(user, { get(target, prop, receiver) { console.log(`Читаємо ${prop}`); return Reflect.get(target, prop, receiver); } }); ``` Це гарантує, що якщо ти не хочеш змінювати поведінку - вона залишиться "типовою". --- ## Де реально застосовуються пастки - Валідація і захист даних - Логування доступу - Створення "віртуальних" властивостей - Реактивні системи (Vue, MobX) - ORM / API-обгортки (наприклад, Prisma Proxy для моделей) - Метапрограмування і тестові моки --- ## ПІДСУМОК | Термін | Що це | |---|---| | **Пастка (trap)** | Метод-обробник у `Proxy`, який "перехоплює" операцію з об'єктом | | **Handler** | Об'єкт, що містить пастки | | **Reflect** | Використовується всередині пасток для виклику стандартної поведінки | | **Target** | Реальний об'єкт, над яким стоїть Proxy |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.