← Назад к вопросам

Что такое прототипное наследование в JavaScript?

1.7 Middle🔥 211 комментариев
#JavaScript Core#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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

Прототипное наследование — это фундаментальный механизм в JavaScript, который отличает его от классических языков программирования (Java, C++). Вместо иерархии классов, JavaScript использует цепочку объектов (prototype chain).

Что такое прототип (Prototype)?

Каждый объект в JavaScript имеет скрытое свойство [[Prototype]] (обращение через __proto__ или Object.getPrototypeOf()), которое ссылается на другой объект — его прототип. Когда обращаешься к свойству объекта, JavaScript ищет его:

  1. Сначала в самом объекте
  2. Затем в его прототипе
  3. Затем в прототипе прототипа
  4. И так до тех пор, пока не найдёт или не дойдёт до null

Это называется prototype chain (цепочка прототипов).

Простой пример

// Создаём объект-прототип
const animal = {
  sound() {
    return "Some sound";
  },
  eat() {
    return "Eating...";
  }
};

// Создаём объект dog с прототипом animal
const dog = Object.create(animal);
dog.bark = function() {
  return "Woof!";
};

console.log(dog.sound()); // "Some sound" — из прототипа!
console.log(dog.eat());   // "Eating..." — из прототипа!
console.log(dog.bark());  // "Woof!" — из самого dog

// Проверяем цепочку
console.log(dog.hasOwnProperty(sound)); // false
console.log(dog.hasOwnProperty(bark));  // true

Цепочка прототипов

const animal = {
  kingdom: "Animalia"
};

const mammal = Object.create(animal);
mamal.type = "Mammal";

const dog = Object.create(mammal);
dog.breed = "Labrador";

console.log(dog.breed);    // "Labrador" — в dog
console.log(dog.type);     // "Mammal" — в mammal
console.log(dog.kingdom);  // "Animalia" — в animal

// Цепочка: dog → mammal → animal → Object.prototype → null

Функции-конструкторы

Традиционный способ создания объектов с наследованием:

// Функция-конструктор
function Animal(name) {
  this.name = name;
}

// Добавляем методы в прототип
Animal.prototype.speak = function() {
  return `${this.name} makes a sound`;
};

// Создаём экземпляр
const dog = new Animal("Dog");
console.log(dog.speak()); // "Dog makes a sound"
console.log(dog instanceof Animal); // true

// Проверяем прототип
console.log(Object.getPrototypeOf(dog) === Animal.prototype); // true

Наследование через функции-конструкторы

// Базовый конструктор
function Animal(name) {
  this.name = name;
}

Animal.prototype.eat = function() {
  return `${this.name} is eating`;
};

// Производный конструктор
function Dog(name, breed) {
  Animal.call(this, name); // Вызываем родительский конструктор
  this.breed = breed;
}

// Настраиваем цепочку прототипов
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // Восстанавливаем конструктор

// Добавляем метод в Dog
Dog.prototype.bark = function() {
  return "Woof!";
};

const myDog = new Dog("Buddy", "Golden Retriever");
console.log(myDog.eat());   // "Buddy is eating" — из Animal
console.log(myDog.bark());  // "Woof!" — из Dog
console.log(myDog instanceof Dog);    // true
console.log(myDog instanceof Animal); // true

Важная строка:

Dog.prototype = Object.create(Animal.prototype);

Эта строка создаёт цепочку: myDog → Dog.prototype → Animal.prototype → Object.prototype → null

Современный подход: классы (синтаксический сахар)

В ES6 появились классы, которые работают на основе прототипного наследования:

// Базовый класс
class Animal {
  constructor(name) {
    this.name = name;
  }
  
  eat() {
    return `${this.name} is eating`;
  }
}

// Производный класс
class Dog extends Animal {
  constructor(name, breed) {
    super(name); // Вызов родительского конструктора
    this.breed = breed;
  }
  
  bark() {
    return "Woof!";
  }
}

const myDog = new Dog("Buddy", "Golden Retriever");
console.log(myDog.eat());   // "Buddy is eating"
console.log(myDog.bark());  // "Woof!"
console.log(myDog instanceof Dog);    // true
console.log(myDog instanceof Animal); // true

Важно: Это просто синтаксический сахар над прототипным наследованием! Под капотом используется всё тот же механизм.

Object.create() для явного управления

const vehicleProto = {
  start() {
    return "Engine started";
  }
};

const carProto = Object.create(vehicleProto);
carProto.drive = function() {
  return "Driving";
};

const myCar = Object.create(carProto);
myCar.model = "Tesla";

console.log(myCar.start());  // "Engine started" — из vehicleProto
console.log(myCar.drive());  // "Driving" — из carProto
console.log(myCar.model);    // "Tesla" — в самом myCar

Проверка принадлежности и свойств

class Animal {}
class Dog extends Animal {}

const dog = new Dog();

// Проверка instanceof (проверяет цепочку прототипов)
console.log(dog instanceof Dog);     // true
console.log(dog instanceof Animal);  // true
console.log(dog instanceof Object);  // true

// Проверка собственного свойства
console.log(dog.hasOwnProperty(age)); // false (если не добавили)

// Проверка наличия в прототипе
console.log(bark in dog); // true (если метод есть в цепочке)

// Получение прототипа
console.log(Object.getPrototypeOf(dog) === Dog.prototype); // true

Преимущества прототипного наследования

  1. Гибкость — можно изменять прототипы во время выполнения
  2. Экономия памяти — методы хранятся в одном прототипе для всех объектов
  3. Динамичность — легко добавлять методы существующим объектам

Частая ошибка

// ❌ НЕПРАВИЛЬНО
function Dog() {}
Dog.prototype = Animal.prototype; // Напрямую присвоили
Dog.prototype.bark = function() {}; // Добавили метод в Animal!

// ✅ ПРАВИЛЬНО
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.bark = function() {}; // Добавили только в Dog

Визуализация цепочки

class Animal {}
class Dog extends Animal {}

const dog = new Dog();

/*
Цепочка прототипов:

dog (объект)
  ↓ [[Prototype]]
Dog.prototype (объект)
  ↓ [[Prototype]]
Animal.prototype (объект)
  ↓ [[Prototype]]
Object.prototype (объект)
  ↓ [[Prototype]]
null
*/

Резюме

  • Прототип — это объект, который другой объект наследует свойства и методы
  • Цепочка прототипов — механизм поиска свойств через цепочку объектов
  • Object.create() — явное создание объекта с указанным прототипом
  • Функции-конструкторы — традиционный способ создания объектов с наследованием
  • Классы — современный синтаксис (ES6+) для прототипного наследования
  • instanceof — проверка принадлежности через цепочку прототипов

Прототипное наследование — это то, что делает JavaScript гибким и мощным. Понимание этого механизма критично для глубокого понимания языка.

Что такое прототипное наследование в JavaScript? | PrepBro