В JavaScript не всегда была возможность создавать классические объекты, которые могут быть созданы на таких языках, как C ++ и Java, но теперь вы можете это сделать с момента разработки EcmaScript 6. В этой статье я расскажу, как создавать классы в JavaScript, включая то, как реализовать конструкторы и методы доступа (геттеры и сеттеры), я расскажу о других аспектах классов JavaScript в будущих статьях.
Классы до EcmaScript 6
В предыдущих версиях JavaScript (EcmaScript) вы не могли создать класс так, как это возможно в таких языках, как C ++ и Java. Вместо этого вам нужно было создать функцию-конструктор, а затем назначить методы прототипу конструктора. Следующий пример демонстрирует эту технику:
function Student(name, id, grades) { this.name = name; this.id = id; this.grades = grades; } Student.prototype.calcAverage = function() { let sum = 0; for (grade of this.grades) { sum += grade; } return sum / this.grades.length; } let stu1 = new Student("Jane Smith", 1234, [81, 77, 92]); print("Grade average: " + stu1.calcAverage()); // displays 83.33333333333
Классические языки объектно-ориентированного программирования (ООП) не так определяют объекты и методы классов, но это был ближайший способ сделать это в предыдущих версиях JavaScript.
Создание классов в JavaScript сейчас
Текущая версия JavaScript теперь позволяет создавать классы, которые более тесно связаны с тем, как их создают классические языки ООП. Давайте начнем с того, что мы можем определить приведенный выше пример студента как класс:
class Student { constructor(name, id, grades) { this.name = name; this.id = id; this.grades = grades; } calcAverage() { let sum = 0; for (let grade of this.grades) { sum += grade; } return sum / this.grades.length; } } let stu1 = new Student("Jane Smith", 1234, [81, 77, 92]); print("Grade average: " + stu1.calcAverage());
Результат этой программы:
Grade average: 83.33333333333
Определение класса больше похоже на то, как это делается в других языках ООП. Ключевое слово class
указывает на то, что определение класса приближается. Конструктор создается не с именем класса, а с ключевым словом constructor
. Тем не менее, как вы можете видеть в примере программы, функция-конструктор по-прежнему вызывается с использованием имени класса.
Определения классов - это синтаксический сахар
Определение класса - это просто синтаксический сахар, который скрывает стандартный способ создания прототипов объектов в JavaScript. Это означает, что я мог бы определить класс Student
выше, используя более старый синтаксис объекта JavaScript, например этот (этот пример изменен из примера в книге Николаса Закаса Понимание EcmaScript 6 на стр. 168):
let Student = function(name, id, grades) { "use strict"; const Student = function(name, id, grades) { if (typeof new.target === "undefined") { throw new Error("Constructor must be called with new."); } this.name = name; this.id = id; this.grades = grades; } Object.defineProperty(Student.prototype, "calcAverage", { value: function() { if (typeof new target !== "undefined") { throw new Error("Method cannot be called with new."); } let sum = 0; for (let grade of this.grades) { sum += grade; } return sum / this.grades.length; }, enumerable: false, writable: true, configurable: true }); return Student; }());
Понятно, что синтаксис класса значительно упрощает создание классов, чем старый способ.
Однако здесь есть несколько вещей, на которые следует обратить внимание. Во-первых, весь код внутри определения класса по умолчанию выполняется в строгом режиме. Кроме того, все методы по умолчанию определены как неперечислимые. Методы класса нельзя вызывать с ключевым словом new
, но конструкторы классов должны вызываться с ключевым словом new.
Как правило, этот новый синтаксис JavaScript для создания классов предоставляет вам множество функций без необходимости писать более сложный объектно-ориентированный синтаксис, необходимый в предыдущих версиях JavaScript.
Конструкторы классов
Как показано в приведенных выше примерах, классы необходимо создавать с помощью конструктора. Вот еще одно определение класса с определенным конструктором:
class Person { constructor(name, age) { this.name = name; this.age = age; } show() { return this.name + ", " + this.age; } }
Если вы не определяете конструктор, система автоматически предоставит вам конструктор по умолчанию. Вот пример, демонстрирующий это:
class Person { show() { return this.name + ", " + this.age; } } let you = new Person(); print(you.show());
Результат этой программы:
undefined, undefined
Несмотря на то, что я не определил метод конструктора, программа не вылетела из-за того, что был создан конструктор по умолчанию и назначен undefined
для name
и age
.
Вы не можете определить конструктор по умолчанию, если у вас уже определен другой конструктор. Классам разрешено только одно определение конструктора или, другими словами, им разрешено одно использование ключевого слова constructor
. Система предоставляет конструктор по умолчанию, если конструкторы не определены или уже определен другой конструктор.
Свойства аксессуара
Полное определение класса предоставляет методы доступа (или свойства в случае JavaScript) для получения и установки значений свойств. Их часто называют геттерами и сеттерами на языках ООП.
Начнем с приобретения действующей собственности. Ключевое слово для использования в определении - get
. Это свойство просто возвращает значение, хранящееся в свойстве. Вот определение класса Person
со свойством получения:
class Person { constructor(name, age) { this.name = name; this.pAge = age; } get age() { return this.pAge; } show() { return this.name + ", " + this.age; } } let me = new Person("John Green", 24); print("Age: " + me.age); // displays Age: 24
Здесь я изменил имя свойства, в котором хранится возраст человека, на pAge
, чтобы можно было использовать age
в качестве свойства-получателя.
Теперь давайте добавим сеттер в определение класса. Наличие установщика позволяет выполнять некоторую проверку данных при установке значения свойства. Например, для свойства age
может быть задано любое допустимое число, поэтому возраст может составлять -2000 или 123 456 лет. Давайте определим сеттер для age
, чтобы он принимал только значения от 0 до 120.
Вот определение нового класса с этим сеттером:
class Person { constructor(name, age) { this.name = name; if (age >= 0 && age <= 120) { this.pAge = age; } else { this.pAge = 0; } } get age() { return this.pAge; } set age(value) { if (value >= 0 && value <= 120) { this.pAge = value; } else { this.pAge = 0; } } show() { return this.name + ", " + this.age; } } let me = new Person("John Green", 24); print("Age: " + me.age); // displays Age: 24 me.age = 121; print("Age: " + me.age); // displays 0 me.age = 25; print("Age: " + me.age); // displays Age: 25
Просматривая определение моего класса, мне также нужно добавить этот код проверки данных в мой конструктор, например:
constructor(name, age) { this.name = name; if (age >= 0 && age <= 120) { this.pAge = age; } else { this.pAge = 0; } }
Другое решение - написать функцию для проверки возраста и вызова функции из конструктора и установщика. Я оставлю это читателю в качестве упражнения.
Далее в части 2
Я лишь прикоснулся к созданию классов в JavaScript. В следующей статье я расскажу о других возможностях классов, в том числе о том, как рассматривать классы как объекты первого класса, вычислять имена членов и статические члены класса. После этой статьи я перейду к наследованию классов в JavaScript.
Благодарим за прочтение. Присылайте комментарии и предложения по адресу [email protected]. Если вас интересуют мои онлайн-курсы по программированию, посетите https://learningcpp.teachable.com.