Одной из его уникальных особенностей JavaScript является использование прототипов для реализации наследования. В этой статье мы разберемся, что такое прототипы, как они работают и как их можно использовать.
Прототип — это другой объект, от которого текущий объект может наследовать свойства и методы. Это позволяет создавать иерархии объектов.
Все объекты JavaScript наследуют свойства и методы от прототипа.
Создаем объект и вызываем методы
Перед продолжением вспоминаем:
- метод — это функция, которая хранится внутри объекта;
- ключевое слово this — ссылка на объект.
Создадим простой объект person, name и age — свойства, sayName() — метод.
const person = {
name: "Сергей",
age: 25,
sayName: function () {
console.log(`Меня зовут ${this.name}`);
},
};
person.sayName(); // Метод sayName() хранится в объекте person
В последней строке вызывается метод объекта sayName() — в консоли отобразилась ожидаемая фраза «Меня зовут Сергей»:
Попробуем вызвать несуществующий метод объекта person sayAge():
const person = {
name: "Сергей",
age: 25,
sayName: function () {
console.log(`Меня зовут ${this.name}`);
},
};
person.sayAge(); // Метода sayAge() у объекта person нет
Поскольку метода sayAge() в объекте person не существует, вылетает ошибка «Uncaught TypeError: person.sayAge is not a function».
Теперь давайте используем метод toString(), которого тоже нет у объекта person:
const person = {
name: "Сергей",
age: 25,
sayName: function () {
console.log(`Меня зовут ${this.name}`);
},
};
console.log(person.toString());
Удивительно, но ошибки нет:
Разгадка заключается в том, что объект person позаимствовал метод toString() у прототипа.
В JavaScript у каждого объекта есть прототип, который можно рассматривать как его родительский объект. Когда вы обращаетесь к свойству объекта и не находите его, JavaScript начнет поиск этого свойства в прототипе объекта. Если нужное свойство не найдено и в прототипе, поиск будет продолжаться в прототипе прототипа и так далее. В конце концов, поиск дойдет до Object.prototype, который является последним в этой цепочке.
Дополнительно рекомендую изучить тему «Встроенные прототипы».
Прототипы
Ссылка на прототип объекта хранится в специальном свойстве, называемом [[Prototype]]. Это свойство не отображается явно в коде и является скрытым. Однако его можно увидеть в инструментах разработчика браузера, например, в консоли, что тает возможность изучить структуру объектов и их прототипов.
Шаг 1. Выводим объект person в консоль браузера:
const person = {
name: "Сергей",
age: 25,
sayName: function () {
console.log(`Меня зовут ${this.name}`);
},
};
console.log(person);
Шаг 2. Смотрим, какие методы есть у прототипа:
Метод Object.getPrototypeOf() возвращает прототип (то есть, внутреннее свойство [[Prototype]]) указанного объекта.1
Object.getPrototypeOf(person);
Прототипное наследование
Рассмотрим пример, который продемонстрирует прототипное наследование. Используем уже знакомый базовый объект person, а затем создадим более специфический объект student, который будет наследовать свойства и методы от person, добавляя некоторые свои уникальные свойства и методы.
Ниже будет использовать метод Object.create(), поэтому немного теории:
Object.create() — метод используется для создания нового объекта с указанным прототипом и, опционально, с заданными свойствами.
const person = {
name: "Сергей",
age: 25,
sayName: function () {
console.log(`Меня зовут ${this.name}`);
},
};
// Создаем объект student, который наследует от person
const student = Object.create(person); // Создаем новый объект student с прототипом person
student.study = function () {
console.log(`${this.name} учится на ${this.subjects}`);
};
// Устанавливаем уникальные свойства для student
student.name = "Алексей"; // Изменяем имя
student.age = 20; // Изменяем возраст
student.subjects = "программиста"; // Добавляем, на кого учится студент
// Используем методы из person и student
student.sayName(); // "Меня зовут Алексей"
student.study(); // "Алексей учится на программиста."
// Проверяем доступ к свойствам объекта person
console.log(`${student.name} - ${student.age} лет`); // "Алексей - 20 лет"
// Проверяем доступ к методу toString()
console.log(student.toString()); // [object Object]
// Выводим объект student в консоль
console.log(student);
Методы toString(), hasOwnProperty() и другие, находятся в объекте Object.prototype, который является конечным прототипом в цепочке прототипов. Это значит, что если вы попытаетесь получить доступ к этим методам у любого объекта, который не имеет своих собственных реализаций, JavaScript будет искать их в Object.prototype.
У прототипа есть свой собственный прототип, что создает цепочку прототипов. Объекты наследуют свойства и методы у прототипов.
Объект без [[Prototype]]
Можно создать объект без свойства [[Prototype]], используя уже знакомый метод Object.create(), прописав в качестве обязательного аргумента null:
const nemo = Object.create(null);
nemo.name = "Капитан Немо";
console.log(nemo);
Объект, созданный с помощью Object.create(null)
, не имеет методов, свойств и прототипа, которые доступны в обычных объектах, что делает его «чистым» объектом.
Попробуем использовать метод toString(), который исправно отрабатывал во всех предыдущих примерах:
const nemo = Object.create(null);
nemo.name = "Капитан Немо";
console.log(nemo.toString());
Чтобы заставить исправно работать метод toString() в примере выше, можно установить ему прототип Object.prototype. Для этого используем современный метод Object.setPrototypeOf()2:
const nemo = Object.create(null);
nemo.name = "Капитан Немо";
Object.setPrototypeOf(nemo, Object.prototype);
console.log(nemo.toString());
console.log(nemo);
Свойство __proto__
Свойство __proto__ доступно на всех объектах и позволяет получить или установить прототип объекта. Однако это свойство не является частью официального стандарта ECMAScript и было введено в браузерах как экспериментальная функция. Хотя оно все еще поддерживается в большинстве современных браузеров, его использование может привести к проблемам с кросс-браузерной совместимостью и не является лучшей практикой.
Рекомендуемые альтернативы:
- Для получения прототипа объекта используйте Object.getPrototypeOf(obj).
- Для установки прототипа используйте Object.setPrototypeOf(obj, prototype).
Таким образом, хотя proto все еще работает и доступно, лучше использовать более стандартизированные методы для работы с прототипами в JavaScript.
Оставьте первый комментарий