Общее представление о прототипах

Прототип - это «резервное хранилище свойств и методов» объекта, автоматически используемое при поиске. Прототипы являются удобными языковыми средствами для определения свойств и функциональных возможностей, которые автоматически становятся доступным для других объектов. Они служат той же цели, что и классы в традиционных объектно-ориентированных языках программирования. В JavaScript они применяются для написания кода объектно-ориентированном стиле.

Объекты в JavaScript являются коллекциями именованных свойств со значениями.

let obj = {
    prop1: 1,
    prop2: function(){},
    prop3: {}
}

Свойствам объекта можно присваивать простые значения, функции и другие объекты. Кроме того, свойства объекта можно легко изменять, удалять благодаря высокой степени динамичности JavaScript.

obj.prop1 = 1;
obj.prop1 = [];
delete obj.prop2;

При написании кода, нужно стремиться повторно использовать код как можно больше. Одной из таких форм повторного использования кода служит наследование, расширяющее возможности одного объекта в другом. В языке JavaScript наследование реализуется путем прототипов.

У каждого объекта может быть ссылка на свой прототип т.е. объект, в котором будет выполняться поиск конкретного свойства, если оно отсутствует у самого объекта.

// создаем три объекта, каждый со своим свойством
const foo = {name1: 'Denis'};
const bar = {name2: 'Liza'};
const baz = {name3: 'Nadia'};

Object.setPrototypeOf(foo, bar); // устанавливаем прототип. Объект bar будет задан в качестве прототипа объекта foo
Object.setPrototypeOf(bar, baz);

console.log('name3' in foo); // true

Проверить, имеется ли у объекта доступ к конкретному свойству, можно с помощью операции in. После установки прототипов объекту foo, доступно свойство name3, объекта baz.

Ссылка на прототип в объекте JavaScript хранится в его внутреннем свойстве, к которому нельзя непосредственно получить доступ из кода, и поэтому оно обозначается как [[prototype]]. Поэтому для установки прототипов используется встроенный метод Object.setPrototypeOf(), которому в качестве аргументов передаются два объекта: второй из них будет служить прототипом первого.

Всякий раз, когда запрашивается значение свойства, которое отсутствует у объекта foo, поиск этого свойства выполняется в объекте bar и т.д. Таким образом можно образоваться цепочка прототипов.