Прототипная цепочка
Прототипная цепочка — механизм наследования в JavaScript: каждый объект имеет внутреннюю ссылку
[[Prototype Pattern]]на другой объект (прототип), и при поиске свойства движок проходит по всей цепочке доnull.
Зачем нужно
Прототипная цепочка — основа всего наследования в JavaScript. Понимание этого механизма объясняет, откуда у любого объекта берутся методы toString, hasOwnProperty, valueOf, как работает extends у классов и почему изменение прототипа влияет на все экземпляры.
Где используется
- Наследование методов в классах (ES6+) и функциях-конструкторах
- Расширение встроенных типов (не рекомендуется, но важно понимать)
- Паттерны: Mixin, Delegation, Object.create-based inheritance
- Понимание
instanceofиhasOwnProperty
Как работает поиск свойства
const animal = {
breathe { return 'дышит'; }
};
const dog = Object.create(animal); // dog.[[Prototype Pattern]] = animal
dog.bark = function { return 'Гав!'; };
const rex = Object.create(dog); // rex.[[Prototype Pattern]] = dog
rex.name = 'Рекс';
// Поиск rex.bark:
// 1. Есть ли у rex? → нет
// 2. Есть ли у dog (прототип rex)? → да → возвращаем
console.log(rex.bark); // 'Гав!'
// Поиск rex.breathe:
// 1. rex → нет
// 2. dog → нет
// 3. animal → да → возвращаем
console.log(rex.breathe); // 'дышит'
// Поиск rex.unknown:
// ... проходим всю цепочку до null → undefined
console.log(rex.unknown); // undefined
Цепочка в диаграмме
rex → dog → animal → Object.prototype → null
name bark breathe toString, hasOwnProperty...
Object.create и явная цепочка
const vehicle = {
type: 'транспорт',
move { return `${this.type} движется`; }
};
const car = Object.create(vehicle);
car.type = 'автомобиль';
car.honk = function { return 'Би-би!'; };
const tesla = Object.create(car);
tesla.type = 'электромобиль';
console.log(tesla.move); // 'электромобиль движется'
console.log(tesla.honk); // 'Би-би!'
// Проверка цепочки
console.log(Object.getPrototypeOf(tesla) === car); // true
console.log(Object.getPrototypeOf(car) === vehicle); // true
Прототип и классы
ES6-классы — синтаксический сахар над прототипной цепочкой:
class Animal {
constructor(name) { this.name = name; }
speak { return `${this.name} издаёт звук`; }
}
class Dog extends Animal {
speak { return `${this.name} лает`; }
fetch { return `${this.name} приносит мяч`; }
}
const rex = new Dog('Рекс');
// Методы живут на прототипе, не на экземпляре
console.log(rex.hasOwnProperty('name')); // true — собственное
console.log(rex.hasOwnProperty('speak')); // false — на прототипе
console.log(Object.getPrototypeOf(rex) === Dog.prototype); // true
console.log(Object.getPrototypeOf(Dog.prototype) === Animal.prototype); // true
Изменение прототипа влияет на все экземпляры
function Person(name) { this.name = name; }
const ivan = new Person('Иван');
const anna = new Person('Анна');
// Добавляем метод на прототип — доступен всем экземплярам
Person.prototype.greet = function {
return `Привет, я ${this.name}`;
};
console.log(ivan.greet); // 'Привет, я Иван'
console.log(anna.greet); // 'Привет, я Анна'
// Метод не копируется в каждый экземпляр — только ссылка через [[Prototype Pattern]]
Частые ошибки
1. Прямое присвоение __proto__ в продакшне
// Устаревший синтаксис — не используй
obj.__proto__ = proto;
// Правильно:
const obj = Object.create(proto);
// или
Object.setPrototypeOf(obj, proto); // медленнее, нарушает оптимизацию V8
2. Расширение Object.prototype — загрязняет глобально
Object.prototype.myMethod = function {}; // опасно!
// Появится в каждом for...in, ломает чужой код
3. Создание объекта с null-прототипом
const plain = Object.create(null); // нет [[Prototype Pattern]]
plain.hasOwnProperty() // undefined — метод недоступен!
// Используй Object.prototype.hasOwnProperty().call(plain, 'key')
Цепочка — это частный случай Delegation Chain
Поиск свойства, разрешение идентификаторов, цепочка scope — всё построено на одном универсальном принципе Delegation Chain: единственная связь к следующему звену, никаких колец.
«Один принцип объясняет сразу пять механизмов JavaScript: prototype chain, разрешение идентификаторов, окружения, поведение генераторов и работу Object» — автор, Part 3.
Производительность: длина цепочки
«Уход вглубь — это лишнее время. Если свойство в конце цепочки, поиск долгий. При промахе движок проходит до самого
null».
Из-за этого глубокие иерархии наследования замедляют не только модификацию, но и чтение методов. См. Антипаттерны ООП.
Связанные темы
- Методы прототипа -- hasOwnProperty, isPrototypeOf
- Конструкторы
- Оператор instanceof
- Миксины (Mixins)
- Delegation Chain
- Пять способов наследования
- Внутренние методы Object (спецификация)
- _MOC ООП
- _MOC JavaScript
Источники
- AsForJS · JavaScript курс. Part 3 Delegation Chain (2026-04-19) — фундаментальный
- Timur · Прототипное программирование и наследование (2019-11-19)
- AsForJS · Что такое Object согласно официальной спецификации (2025-02-03)
- MDN — Inheritance and the prototype chain
- JavaScript.info — Прототипное наследование