Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Object.create()». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`Object.create(proto, propertiesObject)` створює новий об'єкт і вручну призначає йому прототип:** те, що передали першим аргументом, стає `[[Prototype]]` нового об'єкта, тож усі його властивості й методи доступні через ланцюг прототипів. Другий, необов'язковий аргумент описує власні властивості дескрипторами, як у `Object.defineProperty()`. Окремий випадок, `Object.create(null)`, дає «чистий» об'єкт без прототипу, без `toString` і `hasOwnProperty`, ідеальний як словник. ```javascript const dog = Object.create(animal); // Object.getPrototypeOf(dog) === animal ``` **Ключове:** `Object.create()` задає прототип явно, тому це найпростіший спосіб прототипного наслідування без класів і конструкторів.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`Object.create()` - це один із базових методів роботи з прототипами в JavaScript: він створює новий об'єкт, якому ви вручну вказуєте прототип, тобто те, від чого об'єкт успадковує.** Другим аргументом можна одразу описати власні властивості дескрипторами. ## Теорія ### TL;DR - Синтаксис: `Object.create(proto, [propertiesObject])`. - `proto` стає `[[Prototype]]` нового об'єкта, перевірити можна через `Object.getPrototypeOf()`. - Другий аргумент задає власні властивості у форматі дескрипторів, як у `Object.defineProperty()`. - `Object.create(null)` створює об'єкт зовсім без прототипу, зручний для словників. - Це найпростіший спосіб прототипного наслідування без `class` і конструкторів. - Новий об'єкт не копіює властивості прототипу, він лише посилається на нього. ### Швидкий приклад ```javascript const user = { sayHi() { console.log(`Привіт, ${this.name}!`); } }; const alice = Object.create(user); // об'єкт, що успадковує від user alice.name = 'Alice'; alice.sayHi(); // "Привіт, Alice!" ``` Тут `user` є прототипом (`[[Prototype]]`) для `alice`. Власного методу `sayHi` в `alice` немає, він успадкований через прототип. ### Синтаксис і параметри ```javascript Object.create(proto, [propertiesObject]) ``` | Параметр | Опис | | --- | --- | | `proto` | Об'єкт, який стане прототипом нового об'єкта (або `null`) | | `propertiesObject` (необов'язковий) | Додаткові власні властивості у форматі дескрипторів | Перевірити результат можна так: ```javascript console.log(Object.getPrototypeOf(alice) === user); // true ``` `Object.create()` буквально створює новий об'єкт, чий прихований `[[Prototype]]` дорівнює `user`. ### Об'єкт без прототипу ```javascript const data = Object.create(null); data.a = 1; console.log(data); // { a: 1 } console.log(Object.getPrototypeOf(data)); // null console.log(data.toString); // undefined ``` Такий об'єкт не успадковує нічого, навіть `toString` чи `hasOwnProperty`. Його використовують як чистий словник (map-об'єкт), де ключі приходять ззовні і не повинні конфліктувати з іменами методів `Object.prototype`. Мінус лише один: перевіряти наявність ключа доведеться через `Object.hasOwn(data, key)` або `'a' in data`. ### Другий аргумент: дескриптори властивостей Властивості можна одразу задати з атрибутами, як у `Object.defineProperty()`: ```javascript const person = Object.create({}, { name: { value: 'Alice', writable: false, enumerable: true }, age: { value: 25, writable: true } }); console.log(person.name); // "Alice" person.name = 'Bob'; // не змінить значення console.log(person.name); // "Alice" ``` Другий параметр приймає ті самі атрибути: `value`, `writable`, `enumerable`, `configurable`, а також `get` і `set`. Пам'ятайте, що пропущені атрибути тут теж дорівнюють `false`, тому `age` з прикладу не буде видно в `Object.keys()`. ### Прототипне наслідування без класів Найпряміший спосіб зробити «наслідування» вручну: ```javascript const Animal = { eat() { console.log('Я їм'); } }; const Dog = Object.create(Animal); Dog.bark = function() { console.log('Гав!'); }; Dog.eat(); // "Я їм", успадковано від Animal Dog.bark(); // "Гав!", власний метод ``` Той самий підхід замінює `class`, якщо створення екземпляра винести в метод ініціалізації: ```javascript const UserProto = { init(name) { this.name = name; return this; }, greet() { console.log(`Привіт, ${this.name}`); } }; const user = Object.create(UserProto).init('Alice'); user.greet(); // "Привіт, Alice" ``` Такий стиль часто застосовують у функціональному ООП: без класів, але з наслідуванням через прототип. Підсумок: | Що робить | Приклад | Результат | | --- | --- | --- | | Створює об'єкт із заданим прототипом | `Object.create(proto)` | Новий об'єкт, у якого `[[Prototype]] = proto` | | Створює об'єкт без прототипу | `Object.create(null)` | «Чистий» об'єкт без `toString` і `hasOwnProperty` | | Задає властивості з атрибутами | `Object.create({}, { key: { value: 1 } })` | Аналог `defineProperty()` | | Реалізує наслідування | `const child = Object.create(parent)` | `child` успадковує властивості `parent` | ### Типові помилки - **Плутати прототип із копією.** `Object.create(proto)` не копіює властивості: якщо змінити `proto` пізніше, зміни побачить і нащадок. - **Шукати успадковані ключі в `Object.keys()`.** Там лише власні властивості, а `for...in` навпаки обійде і прототипні, тому в циклах потрібен `Object.hasOwn()`. - **Викликати методи `Object.prototype` на об'єкті з `Object.create(null)`.** `data.hasOwnProperty('a')` кине `TypeError`; правильно `Object.hasOwn(data, 'a')` або `Object.prototype.hasOwnProperty.call(data, 'a')`. - **Забувати про дефолтні `false` у другому аргументі.** Властивість, створена через `propertiesObject` без явних атрибутів, не змінюється і не перелічується. - **Записувати в успадковану властивість і чекати зміни прототипу.** Присвоєння створює власну властивість у нащадка і просто затуляє прототипну (shadowing), а не змінює її.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.