Перейти к содержимому

32. Прототипное наследование

![Иллюстрация к уроку](/lessons/javascript-prototypal-inheritance.png)
Прототипное наследование – это ключевой механизм в JavaScript, позволяющий объектам наследовать свойства и методы от других объектов. Понимание этого механизма – фундамент для эффективной работы с JavaScript.
## Что такое прототипное наследование?
В JavaScript каждый объект имеет прототип. Этот прототип – тоже объект. Когда вы обращаетесь к свойству объекта, JavaScript сначала ищет это свойство непосредственно в самом объекте. Если его там нет, он ищет это свойство в прототипе объекта, затем в прототипе прототипа и так далее, пока не достигнет `null`. Этот процесс называется "прототипной цепочкой".
Представьте себе, что прототип - это родитель, а объект - ребенок. Ребенок наследует черты характера и привычки от родителя.
## Практические примеры кода
### Создание объекта и его прототипа
```javascript
// Создаем объект animal
const animal = {
name: 'Animal',
eat: function() {
console.log('Animal is eating');
}
};
// Создаем объект dog, который наследует от animal
const dog = Object.create(animal);
dog.name = 'Dog'; // Переопределяем свойство name для dog
dog.bark = function() {
console.log('Woof!');
};
// Теперь dog имеет свойства и методы от animal и свои собственные
console.log(dog.name); // Output: Dog
dog.eat(); // Output: Animal is eating
dog.bark(); // Output: Woof!
// Добавим метод в прототип animal
animal.sleep = function() {
console.log('Animal is sleeping');
};
// Теперь dog тоже имеет метод sleep, даже если мы его не определяли напрямую
dog.sleep(); // Output: Animal is sleeping
// Проверка прототипа
console.log(Object.getPrototypeOf(dog) === animal); // Output: true
// Функция-конструктор Animal
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
console.log(this.name + ' is eating');
};
// Создаем объект dog с помощью конструктора
const cat = new Animal('Cat');
cat.eat(); // Output: Cat is eating
// Добавляем метод в прототип Animal после создания объекта cat
Animal.prototype.meow = function() {
console.log("Meow!")
}
cat.meow(); // Output: Meow!

Прототипное наследование активно используется во многих JavaScript-фреймворках и библиотеках, таких как React, Angular и Vue.js. Например, компоненты в React часто наследуют методы и свойства от базового класса React.Component. Это позволяет повторно использовать код и создавать более структурированные приложения.

В DOM API, элементы наследуют свойства и методы от HTMLElement, который в свою очередь наследует от Element, а Element от Node. Это значит, что каждый DOM элемент, например <p> или <div>, имеет доступ к общим методам, таким как appendChild, addEventListener и другим.

  • Каждый объект в JavaScript имеет прототип.
  • Прототип - это тоже объект.
  • Свойства и методы ищутся в прототипной цепочке.
  • Можно изменять прототипы существующих объектов.
  • Конструкторы используются для создания объектов с общим прототипом.
  • Прототипное наследование – важный механизм для повторного использования кода и создания иерархии объектов.
## Интерактивный пример
<Playground client:load
template="static"
files={{
"/index.html": `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
body { background: #1e1e2e; color: #cdd6f4; font-family: sans-serif; padding: 16px; margin: 0; }
button { background: #89b4fa; color: #1e1e2e; border: none; padding: 7px 14px; border-radius: 6px; cursor: pointer; margin: 3px; font-size: 13px; font-weight: 600; }
button:hover { background: #74c7ec; }
.box { background: #313244; border-radius: 8px; padding: 14px; margin: 8px 0; }
.out { background: #181825; border-radius: 6px; padding: 10px; font-family: monospace; font-size: 12px; min-height: 100px; color: #a6e3a1; white-space: pre-wrap; }
h3 { color: #cba6f7; margin: 0 0 10px; font-size: 14px; }
</style>
</head>
<body>
<div class="box">
<h3>Прототипное наследование</h3>
<button onclick="demo1()">Object.create</button>
<button onclick="demo2()">Добавить метод в прототип</button>
<button onclick="demo3()">Проверить цепочку</button>
</div>
<div class="out" id="out">Нажмите кнопку для демонстрации...</div>
<script>
var out = document.getElementById('out');
var animal = {
type: 'Животное',
eat: function() { return this.name + ' ест'; },
toString: function() { return '[' + this.name + ']'; }
};
var dog = Object.create(animal);
dog.name = 'Рекс';
dog.bark = function() { return 'Гав! Я ' + this.name; };
window.demo1 = function() {
var lines = ['// Object.create(animal) — dog наследует от animal'];
lines.push('dog.name = "Рекс"');
lines.push('dog.eat() → "' + dog.eat() + '" (унаследован!)');
lines.push('dog.bark() → "' + dog.bark() + '" (собственный)');
lines.push('Object.getPrototypeOf(dog) === animal: ' + (Object.getPrototypeOf(dog) === animal));
out.textContent = lines.join('\\n');
}
window.demo2 = function() {
animal.sleep = function() { return this.name + ' спит Zzz'; };
var lines = ['// Добавляем метод в прототип ПОСЛЕ создания dog'];
lines.push('animal.sleep = function() { ... }');
lines.push('dog.sleep() → "' + dog.sleep() + '" (dog увидел новый метод!)');
out.textContent = lines.join('\\n');
}
window.demo3 = function() {
var lines = ['// Проверка цепочки прототипов'];
lines.push('dog.hasOwnProperty("name"): ' + dog.hasOwnProperty('name') + ' (своё)');
lines.push('dog.hasOwnProperty("eat"): ' + dog.hasOwnProperty('eat') + ' (из прототипа)');
lines.push('dog instanceof Object: ' + (dog instanceof Object));
lines.push('"eat" in dog: ' + ('eat' in dog) + ' (ищет по цепочке)');
out.textContent = lines.join('\\n');
}
</script>
</body>
</html>`,
}}
/>