Прототипы
JavaScript простым языком
Last updated
Was this helpful?
JavaScript простым языком
Last updated
Was this helpful?
Чтобы лучше всё понять – сразу же создаём простой объект.
Результат:
Попробуем вывести в консоль результат действия функции meow
:
Все логично и просто. Попробуем вызвать несуществующую функцию:
Результат ожидаем:
JavaScript правильно подсказывает – woof
не является функцией. Оно так и есть, ведь мы не определяли эту функцию внутри нашего объекта.
Но, для примера, давай попробуем вызвать ещё один метод, который мы не определяли:
Результат:
Ошибки не произошло. И даже вывелись все данные о нашем объекте.
Попробуем еще:
Результат:
Снова что-то вывелось и снова никакой ошибки. Но как так?
Мы не определяли никакого метода valueOf
внутри нашего объекта, ровно, как и не определяли метод toString
. Магия вне Хогвартса? Нет. Все куда проще.
Еще раз посмотрим на первый пример:
Это наш объект. Показаны все свойства и методы, которые мы определяли: meow
, name
, weight
.
Но что это за свойство __proto__
? Давай посмотрим, что лежит внутри него:
Очень много всего. Непонятно зачем, а главное – непонятно откуда.
Во всём этом списке, мы видим и те методы, которые мы вызывали: valueOf
и toString
.
Когда мы вызывали данные методы, JavaScript искал их сначала в пределах нашего объекта, а так как он не нашел их там, то пошёл искать их в свойство __proto__
.
Давай сначала разберёмся с созданием объекта. Тот синтаксис, который мы использовали для определения нашего объекта cat
является упрощенным:
Мы можем определить это другим методом, тем, который более понятен для самого JavaScript и в который в любом случае, JavaScript приводит наш метод определения:
Т.е. создаётся новый объект типа Object
используя ключевое слово new
. И внутрь этого Object
мы передаём наш объект. В результате ничего абсолютно не меняется. Попробуем вывести объект cat
в консоль:
Результат:
Как видишь, мы поменяли метод инициализации нашего объекта, но абсолютно ничего не поменялось в итоговом результате.
Так как мы создаём все наши объекты используя эту конструкцию new Object(...)
, то от этого самого Object
к нашему объекту добавляются дополнительные свойства, к которым и относится то самое, непонятно откуда взявшееся, до текущего момента, свойство __proto__
.
Получается, все объекты, которые мы создаем основываясь на базовом классе JavaScript - Object
.
У класса Object
имеется свойство prototype
. Посмотрим, что там внутри:
Результат:
И мы видим, что внутри этого свойства лежат те же методы, которые добавились к нашему объекту в свойство __proto__
.
Теперь, примерно объясню, для чего это нужно и как это можно использовать.
Давай в свойство prototype
класса Object
добавим какую-нибудь свою функцию. К примеру, функцию woof
, которую мы пытались вызывать и у нашего объекта, но у нас всплывала ошибка:
Теперь, ничего не меняя в нашем объекте, т.е. он останется такого же вида:
Попробуем вызвать метод woof
:
Результат:
Как видишь, никакой ошибки и всё прекрасно отработало. Ещё раз посмотрим на наш объект в консоли:
Результат:
Метод woof
, который мы добавляли в свойство prototype
объекта Object
успешно передалось в свойство __proto__
нашего объекта, поэтому и не произошло никакой ошибки.
Естественно, даже если мы будем использовать первоначальный синтаксис создания нашего объекта без использования new Object(...)
, то всё равно всё будет работать ровно так же.
Надеюсь, ты уже понял, что с помощью прототипов мы получаем возможность расширять возможности наших объектов. К примеру, если оставить данный метод:
И создать несколько своих объектов, то для каждого из них в свойстве __proto__
добавится метод woof
. Т.е. написав этот метод один раз в базовом классе Object
– мы можем использовать его в неограниченном количестве объектов созданных нами.
У базового класса Object
существует метод create
. Он напрямую связан с прототипами, поэтому я решил рассказать и о нём.
Для того чтобы объяснить, как работает данный метод и что он делает, создадим 2 объекта.
Первый объект будет представлять собой основу для второго. Называться он будет employee
, что в переводе означает работник.
Вывод в консоль нам даст:
Для создания второго объекта нам понадобится метод create
из класса Object
:
Что мы только что сделали? Мы создали новый объект
, который должен описывать работника, являющимся менеджером.
Object.create(employee)
говорит о том, что нужно создать новый объект, прототипом которого будет являться объект employee
.
Давай выведем наш объект в консоль:
Результат:
Объект пустой. И это неудивительно, мы же не задали ему ни одного свойства и метода. Но, что же у него теперь находится в свойстве __proto__
? Смотрим:
А внутри него лежит объект employee
, как мы и заказывали. И как видишь, у этого объекта, тоже есть свое свойство __proto__
:
И как ты заметил это класс Object
.
У нас получилась цепочка:
Создав объект employee
обычным способом, мы получили объект, прототипом которого является базовый класс Object
.
Мы создали объект manager
с помощью Object.create(employee)
, прототипом которого указали объект employee
.
Теперь, имея объект manager
, давай установим для него имя и должность:
Теперь еще раз посмотрим на наш объект:
У нашего объекта появились свои свойства name
и position
, при этом одноименные свойства в прототипе (employee
) никак не изменились.
В целом это всё что нужно знать о прототипах.
Если подытожить, то получается, что прототип – это базовый объект другого объекта. Этот базовый объект присутствует у других объектов и каким-то образом расширяет их возможности.
На самом деле, все предыдущие материалы о типах данных в JavaScript были немного прикрыты страшной тайной. На самом деле в JavaScript – нет строкового типа, числового, логического и т.д. В JavaScript – всё объекты.
Это достаточно просто понять. К примеру, создадим обычную строку:
Несмотря на то, что это обычная строка – у неё есть методы. К примеру:
Мы не определяли этот метод, но он существует. Он переводит всю строку к верхнему регистру.
Это происходит потому, что строковый тип, это на самом деле тоже объект, а именно String
. Который в свою очередь основан на объекте Object
.
Получается, что фактически написав такую вот конструкцию:
Для JavaScript это то же самое что и:
Строка str
на самом деле является объектом класса String
, а прототипом объекта класса String
является объект класса Object
.
Все в JavaScript создается на основе класса Object
. Словом, он здесь главный.