Прототипы и наследование
Наследование в JavaScript устроено не через копирование, как в классических языках, а через делегирование: у каждого объекта есть скрытая ссылка [[Prototype]] на другой объект, и, не найдя свойство у себя, движок идёт по этой ссылке дальше. Так работают и общие методы, и class, и instanceof — всё это надстройки над одной цепочкой ссылок.
Эта тема разбирает механику прототипов снизу вверх: чем __proto__ отличается от .prototype, как устроен поиск по цепочке, как связать объекты через Object.create, как заморозить объект и как перехватить операции через Proxy. Базовую механику самих объектов — дескрипторы, копирование — смотрите в теме Объекты и прототипы. Полная карта — в слоях ниже.
Карта темы
__proto__против.prototype— ссылка экземпляра на свой прототип против свойства конструктора.- Цепочка прототипов — как поиск свойства поднимается по
[[Prototype]]доnull. - Прототипное наследование —
Object.createиsetPrototypeOf, живое разделение методов. - Расширяемость объектов — лестница
preventExtensions→seal→freezeи поверхностность заморозки. - Proxy — обёртка с ловушками (
get,set,has), перехватывающая операции над объектом. - Паттерн enum — эмуляция перечисления через замороженный объект и
Symbol.
Частые ошибки и ловушки
| Ошибка | Последствие |
|---|---|
Путать __proto__ и .prototype | .prototype есть только у функций-конструкторов, __proto__ — у экземпляра |
| Ждать, что метод подкласса переопределит стрелочное поле-класс | Стрелочное поле — собственное свойство, оно затеняет метод прототипа |
Считать Object.freeze глубоким | Заморозка поверхностная — вложенный объект остаётся мутабельным |
Менять прототип на лету через setPrototypeOf в горячем коде | Резко ломает оптимизации движка — дорогая операция |
Думать, что пропущенная ловушка Proxy блокирует операцию | Пропущенная ловушка проходит к цели без изменений |
Использовать обычный объект как enum без freeze | Значения можно переписать, «константы» перестают быть константами |
Значение для собеседований
Прототипы — способ отличить того, кто понимает модель объектов JavaScript, от того, кто выучил class. Кандидат, который объясняет new через «создаёт объект и связывает его [[Prototype]] с Ctor.prototype», сразу показывает глубину.
Что обычно проверяют:
- Разница
__proto__(ссылка экземпляра) и.prototype(свойство конструктора). - Как идёт поиск свойства по цепочке и где она кончается.
- Как связать наследование через
Object.create. - Чем
preventExtensions,sealиfreezeотличаются. - Что такое
Proxyи как работают его ловушки.
Типичный неверный ответ: «__proto__ и prototype — это одно и то же». На самом деле .prototype есть только у функций и задаёт прототип будущих экземпляров, а __proto__ — это ссылка конкретного экземпляра на свой прототип. Для нового объекта (new Foo).__proto__ === Foo.prototype.