Введение
JavaScript — это язык, основанный на прототипах, и каждый объект в JavaScript имеет скрытое внутреннее свойство, называемое [[Prototype]]
, которое можно использовать для расширения свойств и методов объекта.
Спецификация языка ECMAScript 2015, часто называемая ES6, представила классы на языке JavaScript. Классы в JavaScript на самом деле не предлагают никаких дополнительных функций и часто описываются как «синтаксический сахар» по сравнению с прототипами и наследованием, поскольку они предлагают более чистый и элегантный синтаксис. Поскольку в других языках программирования используются классы, синтаксис классов в JavaScript облегчает разработчикам переход между различными языками.
Классы — это функции
Класс JavaScript — это тип функции. Классы объявляются с помощью ключевого слова class
. Мы будем использовать синтаксис выражения функции для инициализации функции и синтаксис выражения класса для инициализации класса.
//Initializing a function with a function expression
const x = function() {}
//Initializing a class with a class expression
const y = class {}
Мы можем получить доступ к [[Prototype]]
объекта с помощью Object.getPrototypeOf()
. Давайте используем его для тестирования пустой функции, которая у нас есть.
Object.getPrototypeOf(x);
ƒ () { [native code] }
Мы также можем использовать этот метод в только что созданном классе.
Object.getPrototypeOf(y);
ƒ () { [native code] }
Код, объявленный с function
и class
, возвращает функцию [[Prototype]]
. С прототипами любая функция может стать экземпляром конструктора с использованием new
ключевого слова.
const x = function() {}
//Initialize a constructor from a function
const constructorFromFunction = new x();
console.log(constructorFromFunction);
x {}
constructor: ƒ ()
Это относится и к классам.
const y = class {}
//Initialize a constructor from a class
const constructorFromClass = new y();
console.log(constructorFromClass);
y {}
constructor: class
Эти примеры конструктора прототипа в остальном пусты, но мы можем видеть синтаксис, оба метода дают один и тот же конечный результат.
Определить класс
Функция- конструктор инициализируется рядом параметров, которые будут назначены как свойства this
, ссылающиеся на саму функцию. По соглашению первая буква идентификатора должна быть заглавной.
Когда мы переведем его в синтаксис класса, показанный ниже, мы увидим, что он устроен очень похоже.
Мы знаем, что функция конструктора должна быть планом объекта с первой буквой инициализатора в верхнем регистре (что необязательно). class
ключевого слова более прямо передает цель нашей функции.
Единственная разница в синтаксисе инициализации заключается в использовании ключевого слова class
вместо function
при присвоении свойств в методе constructor()
.
Определите методы
Обычная практика с функциями-конструкторами заключается в назначении методов непосредственно prototype
, а не инициализации, как показано в следующем методе greet()
.
В классах этот синтаксис упрощается, и метод можно добавить непосредственно в класс. Используя ярлык определения метода, представленный в ES6, определение метода становится еще более лаконичным процессом.
Давайте посмотрим на эти свойства и методы в действии. Мы создадим новый экземпляр Hero
, используя new
ключевое слово, и назначим некоторые значения.
const hero1 = new Hero('Varg', 1);
Если мы напечатаем больше информации о нашем новом объекте с помощью console.log(hero1)
, мы сможем увидеть больше деталей о том, что происходит с инициализацией класса.
Hero {name: "Varg", level: 1}
__proto__:
▶ constructor: class Hero
▶ greet: ƒ greet()
В выводе мы видим, что функции constructor()
и greet()
были применены к __proto__
hero1
[[Prototype]]
, а не непосредственно как метод к объекту hero1
. Хотя это очевидно при создании функций-конструкторов, это не очевидно при создании классов. Классы допускают более простой и лаконичный синтаксис, но при этом жертвуют некоторой ясностью процесса.
Расширить класс
Преимущество функций-конструкторов и классов заключается в том, что они могут быть расширены до новых схем объектов, основанных на родителях. Это предотвращает повторение кода для объектов, которые похожи, но требуют некоторых дополнительных или более специфических функций.
Новые функции-конструкторы могут быть созданы родителем с помощью метода call()
. В приведенном ниже примере мы создадим более конкретный класс персонажей с именем Mage
и назначим ему свойства Hero
с помощью call()
, а также добавим дополнительное свойство.
На этом этапе мы можем создать новый экземпляр Mage
, используя те же свойства Hero
и новое дополнение.
const hero2 = new Mage('Lejon', 2, 'Magic Missile');
hero2
из консоли, мы видим, что создали нового Mage
на основе строителя.
Mage {name: "Lejon", level: 2, spell: "Magic Missile"}
__proto__:
▶ constructor: ƒ Mage(name, level, spell)
В классах ES6 ключевое слово super
используется вместо call
для доступа к основным функциям. Мы будем использовать extends
для ссылки на родительский (родительский) класс.
Теперь мы можем таким же образом создать новый экземпляр Mage
.
const hero2 = new Mage('Lejon', 2, 'Magic Missile');
Мы напечатаем hero2
на консоли и просмотрим вывод.
Mage {name: "Lejon", level: 2, spell: "Magic Missile"}
__proto__: Hero
▶ constructor: class Mage
Вывод практически такой же, за исключением того, что в конструкторе класса [[Prototype]]
он связан с родителем, в данном случае Hero
.
Ниже представлено параллельное сравнение всего процесса инициализации, добавления методов и наследования функции-конструктора и класса.
Хотя синтаксис сильно отличается, основной результат обоих методов почти одинаков. Классы дают нам более лаконичный способ создания чертежей объектов, а функции-конструкторы более точно описывают происходящее.
Вывод
В этом руководстве мы узнали о сходствах и различиях между функциями конструктора JavaScript и классами ES6. И классы, и конструкторы имитируют объектно-ориентированную модель наследования в JavaScript, который является языком наследования на основе прототипов.
Понимание прототипного наследования имеет решающее значение для того, чтобы быть эффективным разработчиком JavaScript. Знание классов чрезвычайно полезно, так как популярные библиотеки JavaScript, такие как React, часто используют синтаксис class
.