Чтобы понять объектно-ориентированное программирование в JavaScript, мы сначала должны понять, что JavaScript не является языком на основе классов. Это может немного сбивать с толку, поскольку class
- ключевое слово, используемое для синтаксиса. В других языках, таких как ruby, мы определяем классы, которые действуют как «чертежи» для объектов. Они служат шаблонами, а объекты - экземплярами этих классов. Наследование атрибутов и методов происходит через классы.
Однако в JavaScript мы используем только объекты для наследования. Классы были введены в ECMAScript 2015. Он не поддерживает объектно-ориентированное программирование на основе классов. Вы можете думать о классах как о функциях, которые также являются объектами! На самом деле JavaScript - это язык, основанный на прототипах, в котором объекты JavaScripts содержат ссылки или ссылки на другие объекты.
Вот пример.
В этом примере мы объявили объект Pet
с помощью метода конструктора. Метод конструктора создает экземпляры объектов со следующими атрибутами: name
, species
и breed
. Затем мы создаем три объекта или трех разных домашних животных, вызывая метод конструктора с new
. Чтобы точно узнать, как выглядит первый объект, мы используем console.log()
. Затем мы видим в консоли браузера следующее:
Как и ожидалось, мы возвращаем наш объект, который имеет соответствующие атрибуты в качестве свойств. Но внизу мы видим это свойство __proto__
. Это ключ к решению того, как наследование работает в JavaScript!
Свойство __proto__ - это частное свойство, содержащее ссылку на другой объект. Этот объект называется его прототипом. Вернемся к примеру и расширим это свойство!
Когда мы раскрываем раскрывающийся список, мы сначала видим метод конструктора, который мы определили в нашем объекте Pet
. Это означает, что свойство __proto__
этого объекта связано с прототипом Pet
. Вот почему объект может получить доступ к этому методу конструктора. Объект-прототип Pet действует как шаблон и позволяет объекту selene
наследовать метод конструктора. А как насчет второго свойства __proto__
? Что ж, давайте расширим его!
На этот раз у нас есть больший список! Похоже, свойство Pet
__proto__
указывает на другой объект-прототип! Но что это могло быть? Важно помнить, что все объекты в JavaScript на самом деле являются экземплярами Object
, класса, представляющего тип данных объекта JavaScript. Глобальный класс Object имеет собственные предопределенные наборы методов и свойств. Эти методы и свойства доступны для объекта Pet. А поскольку объект selene
связан с объектом Pet
prototype, selene
также может получить доступ к этим свойствам. Эта цепочка наследования называется цепочкой прототипов.
Вот визуальное представление того, как выглядит цепочка:
Подведем итоги, потому что это может сбивать с толку! У каждого объекта JavaScript есть объект-прототип. Свойство __proto__
связывает экземпляр объекта с его объектом-прототипом. Этот объект-прототип позволяет наследование методов и свойств. selene
наследует методы и свойства от Pet
прототипа. Pet
prototype имеет свой собственный объект-прототип, который является глобальным Object
прототипом. Прототип Pet
наследует все методы и свойства, связанные с глобальным прототипом Object
.
Как видите, наша цепочка заканчивается глобальным Object
прототипом. Это потому, что глобальный прототип Object
не имеет собственного объекта-прототипа. Этот метод создания цепочки прототипов будет продолжаться вечно, пока объект не получит значение null
для своего объекта-прототипа. Это будет считаться последней цепочкой. Как упоминалось ранее, все объекты JavaScript являются экземплярами Object
. Это означает, что глобальный класс Object
будет последней цепочкой в этой цепочке наследования!
Различия между классовым и прототипным наследованием
Наследование класса:
- экземпляры наследуются от классов («чертежи»)
- создает отношения подкласса
Прототипное наследование:
- экземпляры наследуются от других экземпляров объекта
- допускает выборочное наследование
Если вы чем-то похожи на меня, вы можете быть ошеломлены этой новой информацией. Вот список замечательных ресурсов!
- Освойте интервью на JavaScript: в чем разница между классовым и прототипным наследованием?
- Наследование MDN и цепочка прототипов
- Прототипы объектов MDN
- Статья MDN по ключевому слову
class
- Распространенные заблуждения о наследовании в JavaScript
- Объектно-ориентированное программирование на JavaScript - объяснение с примерами
- Прототипы объектов JavaScript