Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Пошук властивостей у ланцюгу прототипів». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Ланцюг прототипів (prototype chain)** - це порядок, у якому JavaScript шукає властивість об'єкта: спочатку в самому об'єкті, потім у його прототипі, далі в прототипі прототипу, і так аж до `null`. Якщо властивість не знайдено ніде, результат - `undefined`. **Ключове:** пошук завжди йде від самого об'єкта вгору по ланцюгу прототипів, поки властивість не знайдеться або ланцюг не обірветься на `null`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Коротка відповідь Коли ти звертаєшся до властивості об'єкта, наприклад: ```javascript obj.prop ``` JavaScript **шукає цю властивість** у такому порядку: 1. Спочатку в **самому об'єкті** (`obj`); 2. Якщо не знайдено - в його **прототипі** (`obj.__proto__` або `Object.getPrototypeOf(obj)`); 3. Потім - у **прототипі прототипу**, і так далі; 4. Поки не дійде до `null` (вершини ланцюга). Якщо властивість не знайдено ніде - результат `undefined`. Ця послідовність і називається **ланцюг прототипів (prototype chain)**. --- ## Приклад: поетапний пошук ```javascript const animal = { eats: true }; const dog = Object.create(animal); dog.barks = true; console.log(dog.barks); // знайдено в dog → true console.log(dog.eats); // немає в dog → шукаємо в animal → true console.log(dog.toString); // немає в animal → шукаємо в Object.prototype → [Function] console.log(dog.fly); // немає ніде → undefined ``` Ланцюг: ```javascript dog → animal → Object.prototype → null ``` --- ## Візуально ```javascript dog { barks: true } ↑ | animal { eats: true } ↑ | Object.prototype { toString(), hasOwnProperty(), ... } ↑ | null ``` --- ## Алгоритм під капотом (покроково) Коли виконується `obj.prop`: 1. JS перевіряє: чи є властивість `prop` **у самому об'єкті** (власна властивість)? → якщо **так** - повернути її значення. → якщо **ні** - йдемо далі. 2. JS отримує прототип об'єкта: ```javascript const parent = Object.getPrototypeOf(obj); ``` 3. Перевіряє, чи є `prop` у `parent`. 4. Повторює кроки, поки: - властивість знайдена - або прототип дорівнює `null` Все це робиться **динамічно**, без копіювання властивостей. --- ## При записі властивості (`obj.prop = value`) Тут механізм трохи інший: - Якщо властивість **існує в самому об'єкті**, → вона просто перезаписується. - Якщо ні - **створюється нова властивість** в `obj` (не в прототипі). - Прототип взагалі не зачіпається. ```javascript const animal = { eats: true }; const dog = Object.create(animal); dog.eats = false; // створює нову властивість у dog console.log(dog.eats); // false (власна) console.log(animal.eats); // true (у прототипі, не змінилося) ``` --- ## При читанні і записі - різні ланцюги! | Операція | Де шукає | Що робить | |---|---|---| | `obj.prop` (читання) | Шукає в `obj`, потім по ланцюгу вгору | Повертає перше знайдене | | `obj.prop = value` (запис) | Завжди пише в `obj`, якщо `writable: true` | Не змінює прототип | | `delete obj.prop` | Видаляє тільки в `obj` | Не впливає на прототип | --- ## Якщо в ланцюгу є геттер або сеттер Якщо на будь-якому рівні знайдено **геттер** (`get prop()`), він **виконується**. Якщо знайдено **сеттер**, він **виконується при записі**. ```javascript const animal = { get info() { return 'Animal info'; } }; const dog = Object.create(animal); console.log(dog.info); // "Animal info" - викликано геттер у прототипа ``` Тобто прототипи можуть містити "реактивні" властивості, а не тільки дані. --- ## Приклад з "глибоким" ланцюгом ```javascript const a = { level: 'A' }; const b = Object.create(a); const c = Object.create(b); const d = Object.create(c); console.log(d.level); // "A" ``` Пошук проходить 4 об'єкти, перш ніж знайде `level` в `a`. --- ## Оптимізація рушієм JS-рушії (V8, SpiderMonkey та ін.) **оптимізують ланцюг прототипів**: - створюють внутрішні "shape"-карти (структури об'єктів); - кешують знайдені властивості; - при зміні прототипу або властивостей кеш скидається. Тому *змінювати прототип під час виконання* (`Object.setPrototypeOf`) - повільна операція, і її краще уникати. --- ## Приклад: що буде, якщо прототип - `null` ```javascript const pure = Object.create(null); pure.key = 'value'; console.log(pure.toString); // undefined (немає Object.prototype) ``` Тут ланцюг обривається одразу: ```javascript pure → null ``` Пошук припиняється миттєво, якщо прототип дорівнює `null`. --- ## ПІДСУМОК | Етап | Що відбувається | |---|---| | 1 | JS шукає властивість у самому об'єкті | | 2 | Якщо не знайдено - йде в `[[Prototype]]` | | 3 | Продовжує вгору по ланцюгу | | 4 | Якщо дійшов до `null` - повертає `undefined` | | Примітка | При записі створюється нова властивість в об'єкті, не в прототипі | | Примітка | Геттери/сеттери в ланцюгу теж враховуються |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.