Прототип JavaScript
Оригинальное название: JavaScript prototype
Коротко
Объект, к которому JavaScript обращается за свойством или методом, если их нет у самого объекта. Так в языке устроено наследование.
Что такое «Прототип JavaScript»
В большинстве популярных языков наследование строится на классах: класс-потомок расширяет класс-родитель. JavaScript устроен иначе. У каждого объекта есть скрытая ссылка на другой объект — прототип. Когда программа читает свойство, движок сначала ищет его у самого объекта, затем у прототипа, затем у прототипа прототипа, и так до конца цепочки. Последнее звено обычно Object.prototype, а его прототип — null. Если свойство не нашлось нигде, результат — undefined.
Благодаря этому у любого массива есть методы map и filter: они хранятся не в каждом массиве, а один раз в Array.prototype.
Как это выглядит в коде
const product = {
label() { return `${this.name} — ${this.price}`; }
};
const sofa = Object.create( product ); // product становится прототипом
sofa.name = 'Диван';
sofa.price = 45000;
sofa.label(); // метод найден в прототипе
Object.getPrototypeOf( sofa ) === product; // true
sofa.hasOwnProperty( 'label' ); // false — своего свойства нет
Прототипы и классы
Синтаксис class появился в ES2015, но внутри работает всё тот же механизм. Методы, объявленные в классе, попадают в объект Имя.prototype, а extends связывает прототипы в цепочку. Поэтому знание прототипов объясняет поведение, которое иначе кажется странным: например, почему метод, изменённый в прототипе, сразу меняется у всех созданных ранее объектов. Классическое наследование в Java или PHP копирует структуру класса, а прототипное — делегирует поиск по живой ссылке.
Чего не делать
- Не расширять встроенные прототипы вроде
Array.prototypeсвоими методами. Старые библиотеки так делали, и это не раз мешало развитию языка: новый стандартный метод конфликтовал с самодельным на тысячах сайтов. - Не сливать в объект непроверенный JSON от пользователя рекурсивной функцией. Ключ
__proto__в таких данных может изменить прототип всех объектов приложения — эту уязвимость называют загрязнением прототипа (prototype pollution). - Не путать собственные свойства объекта с унаследованными: цикл
for...inперебирает и те и другие, аObject.keys()— только собственные.

