Прототипи та прототипне наслідування в JavaScript
Прототипне наслідування є основою об'єктної моделі в JavaScript. На відміну від класичних мов (Java, C++), які використовують класичне наслідування, JavaScript реалізує динамічну модель, де об'єкти можуть успадковувати пропси та методи один від одного через прототипи.
Що таке Прототип?
Прототип — це об'єкт, на який будь-який інший об'єкт посилається, якщо він не має шуканої пропси чи методу. Кожен об'єкт у JavaScript може мати інший об'єкт, призначений як його прототип. Якщо властивість не існує на самому об'єкті під час доступу, інтерпретатор "підніметься" по ланцюгу прототипів до тих пір, поки не знайде потрібну властивість або не досягне об'єкта null.
childObject
parentObject
Object.prototype
null
- childObject: об'єкт, в якому виконується пошук пропси.
- parentObject: прототип childObject.
- Object.prototype: базовий прототип, від якого успадковують всі об'єкти, якщо не вказано інше.
- null: кінець ланцюга; якщо властивість не знайдена до цього моменту, результат буде undefined.
Властивість [[Prototype]] та proto
У специфікації ECMAScript кожен об'єкт має внутрішню властивість [[Prototype]], що вказує на прототип. Історично багато середовищ (наприклад, браузери) надають геттер/сеттер __proto__ для доступу до неї, але це вважається застарілим.
Сучасний спосіб — Object.getPrototypeOf та Object.setPrototypeOf
const parent = { greet: function() { console.log("Hello!"); } };
const child = {};
// Встановлюємо parent як прототип child
Object.setPrototypeOf(child, parent);
// Тепер child має доступ до greet() через ланцюг прототипів
child.greet(); // "Hello!"
console.log(Object.getPrototypeOf(child) === parent); // trueObject.create
Найзручніший спосіб створити об'єкт з потрібним прототипом — це використання методу Object.create
const person = {
sayName() {
console.log(`My name is ${this.name}`);
},
};
const john = Object.create(person);
john.name = "John";
john.sayName(); // My name is John- person виступає як "батько" (прототип).
- john — новий об'єкт, чий [[Prototype]] вказує на person.
Ланцюг Прототипів
Якщо ми викликаємо властивість/метод john.sayName(), і john не має такої пропси, JS шукатиме цю властивість у person. Якщо person не має sayName, інтерпретатор перейде до person.__proto__, який зазвичай є Object.prototype, і так далі.
Конструкторські Функції та Властивість прототипу
Перед появою класів в ES6 (ES2015) конструкторські функції часто використовувалися для імітації поведінки класу.
function User(name) {
this.name = name;
}
User.prototype.sayHi = function () {
console.log(`Hi, I'm ${this.name}`);
};
const alice = new User("Alice");
const bob = new User("Bob");
alice.sayHi(); // "Hi, I'm Alice"
bob.sayHi(); // "Hi, I'm Bob"User— це конструкторська функція.- Властивість
User.prototypeавтоматично створюється, коли функцію оголошено, і вона стає прототипом для всіх об'єктів, створених за допомогоюnew User(...). aliceтаbobзберігають посилання на властивість екземпляра name, а методи беруться з User.prototype.
Класи та Прототипне Наслідування
У сучасних версіях JS ви можете використовувати клас, який під капотом все ще працює на прототипах:
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, I'm ${this.name}`);
}
}
const tom = new Person("Tom");
tom.greet(); // "Hello, I'm Tom"
// Перевірка прототипу
console.log(Object.getPrototypeOf(tom) === Person.prototype); // true- Компілер створює конструкторську функцію
Personі встановлює властивістьPerson.prototype. Усі методи, визначені всерединіclass Person {}, записуються вPerson.prototype.
Підсумок
- Прототип — це механізм, що дозволяє об'єктам успадковувати пропси та методи від інших об'єктів.
- У JS кожен об'єкт має приховану властивість [[Prototype]], зазвичай посилаючись на інший об'єкт або null.
- Ланцюг прототипів дозволяє шукати властивість "знизу-вгору": від об'єкта до його прототипу, потім до прототипу прототипу і так далі.
- Конструкторські функції (до ES6) та класи (з ES6) використовують прототипи "під капотом". Класи є просто "синтаксичним цукром" над конструкторськими функціями.
- Object.create — зручний спосіб створення об'єктів, вказуючи прототип безпосередньо. Прототипне наслідування забезпечує потужний, гнучкий підхід до реалізації ООП без суворого зв'язування з класами.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.