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

Prototype Chain

В одной фразе: прототипная цепочка — механизм делегирования свойств в JS: при обращении к свойству движок ищет его на объекте, затем поднимается по [[Prototype]] до Object.prototype, где цепочка заканчивается null. На собесе важно разграничить proto, .prototype и Object.getPrototypeOf().

[instance]─[[P]]─>[Foo.prototype]─[[P]]─>[Object.prototype]─[[P]]─>null
.x=1              .greet()                .toString()
.constructor=Foo        .hasOwnProperty()
function Foo(x) { this.x = x; }
Foo.prototype.greet = function () { return `x=${this.x}`; };
const obj = new Foo(1);
// Поиск свойства: own → Foo.prototype → Object.prototype
obj.x; // 1 — own property
obj.greet(); // 'x=1' — из Foo.prototype (делегирование)
obj.toString(); // '[object Object]' — из Object.prototype
obj.hasOwnProperty('x'); // true
obj.hasOwnProperty('greet'); // false — greet на prototype, не на obj
// Object.create: задать [[Prototype]] явно
const animal = {
breathe() { return `${this.name} breathes`; }
};
const dog = Object.create(animal);
dog.name = 'Rex';
dog.breathe(); // 'Rex breathes' — делегирует к animal
// Object.create(null): объект без цепочки — чистый словарь
const dict = Object.create(null);
dict.key = 'value';
dict.toString; // undefined — нет Object.prototype в цепочке
// Безопасен для хранения произвольных ключей (нет коллизий с toString и др.)
// Разбираем три "прото":
function Bar() {}
const b = new Bar();
// 1. Bar.prototype — объект где хранятся методы для экземпляров
// 2. Object.getPrototypeOf(b) — [[Prototype]] экземпляра b
// 3. b.__proto__ — устаревший геттер (не использовать в продакшене)
Bar.prototype === Object.getPrototypeOf(b); // true
b instanceof Bar; // true (ищет Bar.prototype в цепочке [[Prototype]] b)
b instanceof Object; // true (Object.prototype тоже в цепочке)

Итог: Prototype chain — живые ссылки: добавление метода в Foo.prototype после создания экземпляров сразу видно всем экземплярам.