В першій главі цього розділу, ми згадували сучасні методи роботи з прототипом.
Встановлення або читання прототипу за допомогою obj.__proto__ вважається застарілим і не рекомендуються для використання в майбутньому (перенесено до так званого “Annex B” стандарту JavaScript, призначеного лише для браузерів).
Сучасні методи отримання/встановлення прототипу:
- Object.getPrototypeOf(obj) – повертає значення
[[Prototype]]об’єктуobj. - Object.setPrototypeOf(obj, proto) – встановлює значення
[[Prototype]]об’єктуobjрівнеproto.
Єдине використання __proto__, яке не викликає негативного ставлення, це як властивість під час створення нового об’єкта: { __proto__: ... }.
Хоча і для цього є спеціальний метод:
- Object.create(proto[, descriptors]) – створює порожній об’єкт із заданим
protoяк[[Prototype]]і необов’язковими дескрипторами властивостей.
Наприклад:
let animal = {
eats: true
};
// створюється новий об’єкт з прототипом animal
let rabbit = Object.create(animal); // same as {__proto__: animal}
alert(rabbit.eats); // true
alert(Object.getPrototypeOf(rabbit) === animal); // true
Object.setPrototypeOf(rabbit, {}); // змінює прототип об’єкту rabbit на {}
Object.create має необов’язковий другий аргумент: дескриптори властивостей.
Ми можемо надати додаткові властивості новому об’єкту, як тут:
let animal = {
eats: true
};
let rabbit = Object.create(animal, {
jumps: {
value: true
}
});
alert(rabbit.jumps); // true
Формат дескрипторів описаний в цій главі Прапори та дескриптори властивостей.
Ми можемо використати Object.create, щоб клонувати об’єкт ефективніше ніж циклом for..in:
let clone = Object.create(
Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)
);
Таким чином ми створюємо справжню копію об’єкта obj, включаючи всі властивості: перелічувані та не перелічувані, сетери/гетери – з правильним значенням [[Prototype]].
Коротка історія
Якщо порахувати всі способи керування властивістю [[Prototype]], їх буде багато! Багато способів робити одне й те ж саме! Як так сталося? Чому?
Так склалося історично.
Прототипна спадковість була в мові з самого початку, але способи керування нею розвивалися з часом.
- Властивість
prototypeфункції-конструктора працювала з дуже давніх часів. Це найстаріший спосіб створення об’єктів із заданим прототипом. - Пізніше, в 2012 році, метод
Object.createстав стандартом. Це дало можливість створювати об’єкти з певним прототипом, проте не дозволяло отримувати або встановлювати його. Тому браузери реалізували не стандартний аксесор__proto__, що дозволяв користувачу отримувати та встановлювати прототип в будь-який час, щоб надати розробникам більше гнучкості. - Ще пізніше, в 2015 році, методи
Object.setPrototypeOfтаObject.getPrototypeOfбули додані до стандарту, для того, щоб виконувати аналогічну функціональність як і__proto__. Оскільки__proto__було широко реалізовано, воно згадується в Annex B стандарту як не обов’язкове для не-браузерних середовищ, але вважається свого роду застарілим. - Пізніше, у 2022 році, було офіційно дозволено використовувати