JavaScript это объектно-ориентированный язык, базирующийся на прототипах, а не на классах. Из-за этой разницы базисов менее очевидно то, что JavaScript позволяет создавать иерархии объектов и наследовать свойства и их значения. Попытаемся прояснить ситуацию.
Предполагается, что читатель уже немного знаком с JavaScript и использовал функции JavaScript для создания простых объектов.
Языки на базе классов и языки на базе прототипов
Объектно-ориентированные языки на базе классов, такие как Java и C++, основаны на концепции двух различных сущностей: классов и экземпляров.
Класс определяет все свойства (если рассматривать методы и поля Java или члены C++ как свойства), которые характеризуют определённый набор объектов. Класс это абстракция, а не какой-то определённый член набора объектов, которые он описывает. Например, класс Employee может представлять набор всех служащих/employees.
Экземпляр, с другой стороны, это инстанциация класса; то есть один из его членов. Например, Victoria может быть экземпляром класса Employee, представляя отдельного индивидуума как служащего/employee. Экземпляр имеет в точности те свойства, которые имеет его родительский класс (ни больше, ни меньше).
Язык на базе прототипов, такой как JavaScript, не имеет таких различий: в нем просто имеются объекты. Язык на базе прототипов содержит понятие prototypical object\прототипичный объект – объект, используемый как шаблон, из которого получаются начальные свойства для нового объекта. Любой объект может специфицировать свои собственные свойства, либо когда вы создаёте его, либо на этапе прогона. Кроме того, любой объект может быть ассоциирован как прототип для другого объекта, давая другому объекту возможность использовать свойства первого объекта.
1. Определение класса
В языках на базе классов вы определяете класс в отдельном определении класса. В этом определении вы можете специфицировать специальные методы, называемые конструкторами, которые служат для создания экземпляров класса. Конструктор метода может специфицировать начальные значения для свойств экземпляров и выполнять другую обработку на этапе создания. Вы используете оператор new вместе с конструктором метода для создания экземпляров класса.
JavaScript следует простой модели, но не имеет определения класса отдельно от его конструктора. Вместо этого вы определяете конструктор функции для создания объектов с определённым начальным набором свойств и значений. Любая функция JavaScript может использоваться как конструктор. Вы используете оператор new вместе с конструктором функции для создания новых объектов.
2. Подклассы и наследование
В языках на базе классов вы создаёте иерархию классов через определения классов. В определении класса вы можете специфицировать, что новый класс является subclass\подклассом уже существующего класса. Подкласс наследует все свойства суперкласса (родительского) и может дополнительно вводить новые свойства и модифицировать унаследованные. Например, предположим, что класс Employee имеет только свойства name и dept и что Manager является подклассом от Employee, добавляющим свойство reports. В этом случае экземпляр класса Manager будет иметь все три свойства: name, dept и reports.
JavaScript реализует наследование, позволяя вам ассоциировать прототипичный объект с любым конструктором функции. Так, вы можете создать пример Employee-Manager, но используя при этом слегка иную терминологию. Во-первых, вы определяете конструктор функции Employee, специфицируя свойства name и dept. Затем вы определяете конструктор функции Manager, специфицируя свойство reports. Наконец, вы присваиваете новый Employee-объект как прототип конструктору функции Manager. После этого, когда вы создаёте новый Manager-объект, он наследует it свойства name и dept от объекта Employee.
3. Добавление и удаление свойств
В языках на базе классов вы обычно создаёте класс на этапе компиляции и затем создаёте экземпляры класса на этапе компиляции или на этапе прогона программы. Вы не можете изменить количество или типы свойств класса после того, как вы определили этот класс. В JavaScript, напротив, на этапе прогона вы можете добавлять и удалять свойства любого объекта. Если вы добавляете свойство к объекту, который используется как прототип для набора объектов, эти объекты также получают новое свойство.
4. Различия. Резюме.
В таблице дано краткое резюме по некоторым отличиям. Остальная часть этой главы описывает детали использования конструкторов и прототипов JavaScript для создания иерархии объектов и сравнивает их с теми же процессами в Java.
На базе классов (Java)
На базе прототипов (JavaScript)
Класс и экземпляр класса являются разными сущностями.
Все объекты являются экземплярами.
Определяет класс в определении класса; инстанциирует класс методами-конструкторами.
Определяет и создаёт набор объектов с помощью конструкторов функций.
Создаёт отдельный объект оператором new.
То же самое.
Иерархия объектов конструируется путём использования определения класса для определения подклассов существующих классов.
Иерархия объектов конструируется присвоением объекта как прототипа, ассоциированного с конструктором функции.
Наследует свойства по цепочке классов.
Наследует свойства по цепочке прототипов.
Определение класса специфицирует все свойства всех экземпляров класса. Свойства не могут добавляться динамически на этапе прогона программы.
Конструктор функции или прототип специфицирует начальный набор свойств. Свойства могут удаляться и добавляться динамически в отдельных объектах или сразу для набора объектов.