20-07-24 09:34:37
Основные концепции:
Для понимания прототипного наследование начнем с простого примера. Мы можем создать объект и использовать другой объект в качестве его прототипа.
const animal = {
eats: true,
walk() {
console.log('Животное идет');
}
};
const rabbit = {
jumps: true
};
// Устанавливаем animal в качестве прототипа rabbit
rabbit.__proto__ = animal;
console.log(rabbit.eats); // Вывод: true
rabbit.walk(); // Вывод: Животное идет
В этом примере объект rabbit наследует свойство eats и метод walk от объекта animal.
Хотя прямое задание свойства __proto__ просто, оно не рекомендуется из-за потенциальных проблем с производительностью и читаемостью. Вместо этого мы можем использовать Object.create для создания объекта с указанным прототипом.
const animal = {
eats: true,
walk() {
console.log('Животное идет');
}
};
const rabbit = Object.create(animal);
rabbit.jumps = true;
console.log(rabbit.eats); // Вывод: true
rabbit.walk(); // Вывод: Животное идет
console.log(rabbit.jumps); // Вывод: true
Используя Object.create, мы устанавливаем animal в качестве прототипа rabbit, что позволяет rabbit наследовать свойства и методы от animal.
Конструкторные функции предоставляют более структурированный способ создания объектов и настройки наследования прототипов. Используя ключевое слово new, мы можем создавать экземпляры, наследующие от свойства прототипа конструкторной функции.
function Animal(name) {
this.name = name;
}
Animal.prototype.eats = true;
Animal.prototype.walk = function() {
console.log(`${this.name} идет`);
};
const rabbit = new Animal('Кролик');
console.log(rabbit.eats); // Вывод: true
rabbit.walk(); // Вывод: Кролик идет
В этом примере Animal является конструкторной функцией. Когда мы создаем новый экземпляр Animal с помощью new Animal('Кролик'), объект rabbit наследует свойства и методы от Animal.prototype.
Цепочка прототипов позволяет наследовать свойства и методы через несколько уровней. Давайте расширим наш предыдущий пример, чтобы включить несколько уровней наследования.
function Animal(name) {
this.name = name;
}
Animal.prototype.eats = true;
Animal.prototype.walk = function() {
console.log(`${this.name} идет`);
};
function Rabbit(name, color) {
Animal.call(this, name);
this.color = color;
}
// Наследуем от Animal
Rabbit.prototype = Object.create(Animal.prototype);
Rabbit.prototype.constructor = Rabbit;
Rabbit.prototype.jump = function() {
console.log(`${this.name} прыгает`);
};
const rabbit = new Rabbit('Белый Кролик', 'белый');
console.log(rabbit.eats); // Вывод: true
rabbit.walk(); // Вывод: Белый Кролик идет
rabbit.jump(); // Вывод: Белый Кролик прыгает
Здесь Rabbit является конструкторной функцией, которая наследует от Animal. Мы используем Object.create для настройки цепочки прототипов, что позволяет экземплярам Rabbit наследовать от Animal.prototype.
При настройке наследования прототипов с использованием Object.create важно сбросить свойство constructor на соответствующую конструкторную функцию. Это гарантирует, что экземпляры распознают правильный конструктор.
function Rabbit(name, color) {
Animal.call(this, name);
this.color = color;
}
// Наследуем от Animal
Rabbit.prototype = Object.create(Animal.prototype);
Rabbit.prototype.constructor = Rabbit;
console.log(Rabbit.prototype.constructor === Rabbit); // Вывод: true
Сбросив свойство constructor, мы сохраняем целостность цепочки прототипов и гарантируем, что экземпляры Rabbit правильно ссылаются на свой конструктор.
Прототипные методы общие для всех экземпляров, в то время как экземплярные методы определяются для каждого отдельного экземпляра. Понимание разницы между ними может помочь оптимизировать использование памяти и производительность.
Прототипный метод:
function Animal(name) {
this.name = name;
}
Animal.prototype.walk = function() {
console.log(`${this.name} идет`);
};
const animal1 = new Animal('Собака');
const animal2 = new Animal('Кошка');
console.log(animal1.walk === animal2.walk); // Вывод: true
Экземплярный метод:
function Animal(name) {
this.name = name;
this.walk = function() {
console.log(`${this.name} идет`);
};
}
const animal1 = new Animal('Собака');
const animal2 = new Animal('Кошка');
console.log(animal1.walk === animal2.walk); // Вывод: false
Используя прототипные методы, мы гарантируем, что все экземпляры используют один и тот же метод, уменьшая использование памяти. Экземплярные методы, с другой стороны, создаются для каждого экземпляра, что может увеличить потребление памяти.