32. Прототипное наследование
Прототипное наследование – это ключевой механизм в JavaScript, позволяющий объектам наследовать свойства и методы от других объектов. Понимание этого механизма – фундамент для эффективной работы с JavaScript.
## Что такое прототипное наследование?
В JavaScript каждый объект имеет прототип. Этот прототип – тоже объект. Когда вы обращаетесь к свойству объекта, JavaScript сначала ищет это свойство непосредственно в самом объекте. Если его там нет, он ищет это свойство в прототипе объекта, затем в прототипе прототипа и так далее, пока не достигнет `null`. Этот процесс называется "прототипной цепочкой".
Представьте себе, что прототип - это родитель, а объект - ребенок. Ребенок наследует черты характера и привычки от родителя.
## Практические примеры кода
### Создание объекта и его прототипа
```javascript// Создаем объект animalconst animal = { name: 'Animal', eat: function() { console.log('Animal is eating'); }};
// Создаем объект dog, который наследует от animalconst dog = Object.create(animal);dog.name = 'Dog'; // Переопределяем свойство name для dogdog.bark = function() { console.log('Woof!');};
// Теперь dog имеет свойства и методы от animal и свои собственныеconsole.log(dog.name); // Output: Dogdog.eat(); // Output: Animal is eatingdog.bark(); // Output: Woof!Изменение прототипа
Заголовок раздела «Изменение прототипа»// Добавим метод в прототип animalanimal.sleep = function() { console.log('Animal is sleeping');};
// Теперь dog тоже имеет метод sleep, даже если мы его не определяли напрямуюdog.sleep(); // Output: Animal is sleeping
// Проверка прототипаconsole.log(Object.getPrototypeOf(dog) === animal); // Output: trueИспользование конструкторов
Заголовок раздела «Использование конструкторов»// Функция-конструктор Animalfunction 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 после создания объекта catAnimal.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>`, }}/>