Чтение этого раздела не обязательно для того, чтобы научиться писать сценарии на языке JavaScript. Его назначение состоит в том, чтобы дать представление о внутренних механизмах реализации JavaScript тем программистам, которые имеют опыт работы с другими объектно-ориентированными языками программирования. Если эти детали Вас не интересуют, то можете перейти к следующему разделу.
Прототипы объектов
Большинство объектно-ориентированных языков (например, Java и C++) основаны на двух базовых понятиях: классы объектов и экземпляры (instances) объектов.
- Класс объектов — это абстрактное понятие, описывающее все свойства данного класса (в Java эти свойства называются полями и методами, а в C++ членами класса, но суть от этого не меняется).
- Экземпляр объекта — это реализация класса, т. е. конкретный объект, наделенный всеми свойствами данного класса.
JavaScript, в отличие от этих языков, основан на прототипах и не проводит различия между двумя приведенными понятиями: в нем есть только объекты. Некоторым аналогом класса здесь выступает
прототип объекта, который определяет начальный набор свойств нового объекта.
В процессе выполнения программы объект может получать новые свойства; более того, он может сам выступать в качестве прототипа при создании новых объектов.
В языках, основанных на классах, класс объектов описывается отдельной декларацией класса. В этой декларации мы можем указать специальные методы, называемые
конструкторами, которые создают экземпляры данного класса. Конструктор выделяет память для экземпляра, инициализирует значения его свойств и выполняет другие необходимые действия.
После написания декларации класса мы можем создавать его экземпляры путем вызова операции
new имя_конструктора(...)
.
Создание объектов в JavaScript происходит примерно так же, но здесь декларация конструктора совпадает с декларацией класса. Иными словами, мы определяем конструктор как функцию, которая создает объекты с заданным начальным набором свойств и их значений. Затем мы так же создаем объекты вызовом операции
new имя_конструктора(...)
.
В языках, основанных на классах, классы объектов образуют
иерархию классов, в которой каждый класс может быть потомком какого-либо ранее определенного класса. Потомок класса наследует все его свойства, но может иметь дополнительные собственные свойства или изменять свойства своего предка.
При этом набор свойств данного класса зафиксирован в его декларации и не может быть изменен в ходе выполнения программы. Можно сказать, что здесь текущее состояние реализуется экземплярами классов, методы реализуются классами, а наследование — структурой и поведением.
JavaScript поддерживает наследование, основанное на прототипах. С каждым конструктором связан соответствующий прототип объекта, и каждый объект, созданный конструктором, содержит неявную ссылку на этот прототип.
Прототип, в свою очередь, может содержать ссылку на свой прототип и так далее. Так образуется
цепочка прототипов. Ссылка на свойство объекта — это ссылка на первый прототип в цепочке прототипов объекта, который содержит свойство с данным именем. Иными словами, если данный объект имеет свойство с данным именем, то используется ссылка на это свойство; если нет, то исследуется прототип этого объекта и т. д.
В JavaScript текущее состояние и методы реализуются объектами, а структура и поведение наследуются. Все объекты, которое явно содержат свойство, которое содержит их прототип, разделяют это свойство и его значение.
В отличие от языков, основанных на классах, свойства могут динамически добавляться к объектам и динамически удаляться. В частности, конструкторы не обязаны присваивать значения всем или некоторым свойствам создаваемого объекта.
Перечисленные в этом разделе отличия объектной модели JavaScript от языков, основанных на классах, сведены в следующей таблице.
Модель, основанная на классах
(Java и C++) |
Модель, основанная на прототипах (JavaScript) |
Класс объектов и экземпляр объекта — это различные понятия. |
Все объекты являются экземплярами объектов. |
Класс определяется декларацией класса. Экземпляр класса создается конструктором. |
Набор объектов определяется и создается функцией-конструктором. |
Новый объект создается операцией new. |
Новый объект создается операцией new. |
Существует иерархия классов, в которой новые классы являются потомками ранее определенных. |
Существует иерархия объектов, в которой объект имеет прототип, заданной функцией-конструктором. |
Свойства наследуются по цепочке классов-потомков. |
Свойства наследуются по цепочке прототипов. |
Декларация класса определяет все свойства всех экземпляров данного класса. Набор свойств не может динамически изменяться в ходе выполнения программы. |
Конструктор или прототип определяют начальный набор свойств. Свойства набора объектов или отдельного объекта могут динамически добавляться и удаляться в ходе выполнения программы. |