Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що зберігається в __proto__». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**У `__proto__` зберігається посилання на прототип об'єкта, тобто на той об'єкт, від якого поточний успадковує властивості й методи.** Це доступ до внутрішнього слота `[[Prototype]]`, який можна прочитати і навіть змінити зі звичайного коду, але сучасні й офіційні способи роботи з ним, це `Object.getPrototypeOf()` та `Object.setPrototypeOf()`. ```javascript const animal = { eats: true }; const dog = { barks: true }; dog.__proto__ = animal; // animal стає прототипом dog console.log(dog.eats); // true, успадковано від animal ``` **Ключове:** `__proto__` - це посилання самого об'єкта на прототип, а `prototype` - властивість функції-конструктора, яка стане прототипом її екземплярів.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`__proto__` - це внутрішня властивість об'єкта, яка зберігає посилання на його прототип, тобто на той об'єкт, від якого він успадковує властивості та методи.** Іншими словами, це видимий зі звичайного JavaScript-коду доступ до внутрішнього слота `[[Prototype]]`, який можна не тільки прочитати, а й змінити. ## Теорія ### TL;DR - У `__proto__` лежить об'єкт, який є прототипом поточного об'єкта, або `null`. - Саме за цим посиланням рушій іде, коли не знаходить властивість у самому об'єкті. - `__proto__` об'єкта вказує на `prototype` функції, яка його створила. - `__proto__` і `prototype` - це різні речі: перше в об'єктів, друге у функцій-конструкторів. - Офіційні аналоги: `Object.getPrototypeOf()` і `Object.setPrototypeOf()`. - `Object.prototype.__proto__` дорівнює `null`, це кінець ланцюжка. ### Швидкий приклад ```javascript const animal = { eats: true }; const dog = { barks: true }; dog.__proto__ = animal; // встановлюємо animal як прототип dog console.log(dog.eats); // true, успадковано від animal console.log(dog.barks); // true, власна властивість ``` Що тут відбувається: - у `dog` немає властивості `eats`; - JavaScript шукає її в `dog.__proto__`, тобто в `animal`; - знаходить і повертає `true`. ### Що саме зберігається в `__proto__` У `__proto__` зберігається об'єкт, який виконує роль прототипа для поточного об'єкта. ```javascript const user = { name: 'Alice' }; console.log(user.__proto__ === Object.prototype); // true console.log(Object.prototype.__proto__); // null, кінець ланцюжка ``` Тобто ланцюжок такий: ```text user -> Object.prototype -> null ``` ### Як виглядає ланцюжок для масиву ```javascript const arr = [1, 2, 3]; console.log(arr.__proto__ === Array.prototype); // true console.log(arr.__proto__.__proto__ === Object.prototype); // true console.log(arr.__proto__.__proto__.__proto__); // null ``` Для масиву ланцюжок виглядає так: ```text arr -> Array.prototype -> Object.prototype -> null ``` Саме тому в масиву є і `map()` з `Array.prototype`, і `hasOwnProperty()` з `Object.prototype`. ### `__proto__` не те саме, що `prototype` Це найчастіша плутанина на співбесідах. | Властивість | Де знаходиться | Що робить | | --- | --- | --- | | `__proto__` | в об'єкта | посилання на його прототип | | `prototype` | у функції-конструктора | шаблон для майбутніх об'єктів, тобто їхній прототип | ```javascript function User() {} const alice = new User(); console.log(alice.__proto__ === User.prototype); // true console.log(User.prototype.constructor === User); // true ``` Отже, `__proto__` об'єкта вказує на `prototype` тієї функції, яка його створила. ### Як безпечно працювати з прототипом Сучасні аналоги, яким варто віддавати перевагу перед `__proto__`: ```javascript // Отримати прототип Object.getPrototypeOf(obj); // Встановити прототип Object.setPrototypeOf(obj, proto); ``` Історично `__proto__` був неформальним розширенням рушіїв, і лише потім його стандартизували як застарілий сумісний додаток. Наведені вище методи, навпаки, є офіційною частиною мови. Перевірка, що обидва способи дають той самий результат: ```javascript const animal = { eats: true }; const dog = Object.create(animal); console.log(Object.getPrototypeOf(dog) === animal); // true console.log(dog.__proto__ === animal); // true ``` ### Чому `__proto__` не радять використовувати напряму - Це застарілий (legacy) механізм, залишений у стандарті лише заради сумісності з вебом. - Присвоєння в `__proto__` повільне: воно скидає внутрішні оптимізації рушія для цього об'єкта. - Легко випадково зламати ланцюжок прототипів і втратити стандартні методи. - Об'єкт, створений через `Object.create(null)`, взагалі не має цього аксесора, бо не успадковує від `Object.prototype`. Замість цього використовуйте: ```javascript Object.getPrototypeOf(obj); Object.setPrototypeOf(obj, newProto); ``` Найкраще ж задавати прототип одразу під час створення об'єкта, через `Object.create(proto)` або `class`. ### Підсумок | Властивість | Що зберігає | Де використовується | Сучасна альтернатива | | --- | --- | --- | --- | | `__proto__` | посилання на прототип об'єкта | у всіх об'єктів | `Object.getPrototypeOf()`, `Object.setPrototypeOf()` | | `prototype` | прототип, який отримають нові об'єкти при створенні через `new` | у функцій-конструкторів | немає, це окремий механізм | ### Типові помилки - **Казати, що `__proto__` є у функцій замість `prototype`.** У функції є обидві властивості, і вони означають різне: `__proto__` функції вказує на `Function.prototype`. - **Змінювати `__proto__` у циклі або в гарячому коді.** Це найповільніша операція з прототипами. - **Думати, що `__proto__` копіює властивості.** Він лише зберігає посилання, властивості залишаються в прототипі. - **Приймати дані ззовні в ключ `__proto__` без перевірки.** Наївне злиття JSON з зовнішнього API може підмінити прототип, це класична вразливість prototype pollution. - **Очікувати `__proto__` в об'єкта без прототипа.** Для `Object.create(null)` звернення поверне `undefined` як звичайну відсутню властивість.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.