Прототипы в JS
Прототип - это JS объект, от которого другие объекты наследуют его свойства и методы. По умолчанию, у каждого объекта есть свой прототип и если у искомого объекта не хватает каких-либо свойств, то они ищутся в прототипе. В свою очередь, если и у ближайшего прототипа нет этих свойств, то они ищутся ниже в иерархии прототипов. По такому принципу происходит наследование прототипов в JS.
На вершине цепочки прототипов, находится последний прототип (стандартный объект JavaScript), выше которого уже ничего нет.
Прототип объекта в JS
Чтобы увидеть __proto__ в консоли разработчика, создадим объект - машина.
let car = {
model: 'Mazda'
};
console.log(car);
В консоли вывелось название типа данных - object, внутри которого мы видим ссылку __proto__. Эта ссылка ведет на прототип объекта car. Внутри ссылки мы можем увидеть всю цепочку прототипов, которая рано или поздно закончится значением null.
Пример с консолью, нам наглядно показывает весь механизм наследования прототипов в JS, но практической пользы от этого нет. Все равно все свойства у прототипов, мы будем писать сами.
Прототип функции в JS
А использовать мы будем свойство, которое есть у каждой функции - prototype.
Создадим новый объект user вторым способом, пропишем внутри объекта два свойства и одну функцию, которая будет выводить в консоль строку Privet.
const user = new Object ({
nickname: 'sorax',
age: 25,
write: function(){
console.log('Privet')
}
});
Убедимся, что в консоли мы имеем доступ к полям объекта, обратившись к ним по названию объекта через точку по ключу.
Хорошо, пойдем дальше и если введем в консоль такую запись.
user.toString()
то на выходе получим не ошибку, а следующую запись:
"[object Object]"
Откуда взялась функция toString? Выведем в консоль объект user и увидим знакомую нам ссылку __proto__. Если мы раскроем эту ссылку, то среди внушительного списка методов, мы увидим toString. Это значит, метод toString перешел к объекту user по наследству.
У всех новых созданных объектов обязательно есть прототип. Обратимся к свойству prototype у глобального класса Object и создадим новое поле - функцию sayHello.
Object.prototype.sayHello = function(){
console.log('Hello')
}
Вызовем в консоли новую функцию у объекта user. Никакой ошибки не возникло, функция отработала и вывела Hello.
user.sayHello()
Hello
Обратите внимание, что у объекта user не было функции sayHello, но эта функция появилась у его родителя. Получается, что объект user унаследовал её от родителя (прототипа Object).
Таким образом, мы можем добавлять новые методы и свойства не напрямую в текущий объект, а через его прототип. Что это даёт? Например, можно через общий прототип (класс) быстро вносить изменения в тысячи аккаунтов пользователей.
Создадим нового пользователя fantomas. Передадим в метод create объект user, который будет служить прототипом у нового объекта fantomas.
const fantomas = Object.create(user);
Напечатаем в консоли слово fantomas и нажмем Enter. На верхнем уровне у нас создался пустой объект, что логично. Ведь никаких полей для него, мы не создавали. Но внутри пустого объекта, мы опять увидим __proto__: Object.
{}
Поэтому, если мы напишем fantomas.write(), то увидим в консоли Privet. Как так получилось? У самого объекта fantomas, нет ничего. Выходит, что fantomas, унаследовал функцию write у прототипа.
У объекта fantomas должен быть свой ник, который записался на верхний уровень цепочки наследования. При этом, на более низком уровне старый ник sorax, не перезаписался.
fantomas.nickname = 'fantomas'
Как работает механизм цепочки наследования? Он проверяет сверху вниз, если на верхнем уровне находит какое-то свойство или функцию, то сразу её вызывает. Если он ничего не находит, тогда обращается к прототипу и ищет в нём. И если, ничего не найдено по всей цепочке прототипов, то выдается ошибка. С помощью прототипов, можно легко расширять свойства или методы объектов.
-
- Михаил Русаков
Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.