На предыдущих
занятиях мы с вами работали с объектами, расширяли их по распространенному
синтаксису с использованием свойств:
__proto__ и prototype.
Однако, относительно
недавно в JavaScript появилась
возможность объявлять классы для создания объектов по общепринятому во многих
языках программирования синтаксису – через ключевое слово class:
class <название> {
constructor() { … }
method1() { … }
…
methodN() { … }
}
Например, в
самом простом случае, класс для представления информации о книге можно записать
так:
class Book {
constructor() {
console.log("создание объекта book");
}
}
И, затем, с
помощью оператора new создать объект по этому шаблону:
В результате
увидим строчку «создание объекта book», означающая, что автоматически был
вызван метод constructor класса Book. Если кто не
знает, это специальный метод, который вызывается при создании объекта. В нем
можно выполнять начальную инициализацию каких-либо свойств. Например, мы хотим передавать
объекту, при его создании, несколько параметров:
заголовок,
автор и цена книги
Для этого в
конструкторе определим эти параметры, затем, проинициализируем их, то есть,
создадим соответствующие свойства в объекте:
class Book {
constructor(title, author, price) {
this.title = title;
this.author = author;
this.price = price;
}
}
И при создании
объекта, передадим этим параметрам определенные значения:
let book1 = new Book("Муму", "Тургенев", 112);
Выведем в
консоль этот объект:
и увидим все
эти, созданные в конструкторе, свойства. И, разумеется, ссылка this будет указывать
на новый созданный объект, а не на класс Book.
Затем, в этот
класс можно поместить несколько методов, например, такие:
getTitle() { return this.title; }
setPrice(pr) { this.price = pr; }
Обратите
внимание, мы здесь не пишем ключевое слово function, а объявляем
методы, используя синтаксис объектов, но без запятых в конце.
И, теперь
смотрите, при выводе в консоль объекта book1 мы не увидим в
нем этим методов. Они будут находиться в базовом объекте, на который ссылается
свойство __proto__:
Отличия классов от функций
Здесь может
показаться, что, в действительности, класс в JavaScript работает
наподобие функции-конструктора:
function Book(title, author, price) {
this.title = title;
this.author = author;
this.price = price;
}
Book.prototype.getTitle = function() { return this.title; }
Book.prototype.setPrice = function(pr) { this.price = pr; }
И вы будете близки
к истине. Действительно, если вернуться к классу и отобразить его тип:
console.log(typeof(Book));
то увидим
значение «function». Но есть и
отличия, например, класс создает функцию не в «чистом» виде. Это специальная
функция, которая помечена как
[[FunctionKind]]:"classConstructor"
и без оператора new она не может
быть вызвана. Например, так:
let book1 = Book("Муму", "Тургенев", 112);
Далее, методы
класса автоматически помечаются как неперечисляемые и не выводятся с помощью
цикла for in:
for(let p in book1)
console.log(p+": "+book1[p]);
Наконец, весь
код внутри классов автоматически помечается директивой
"use strict"
Так что отличия
от обычной функции все же есть.
Class Expression
Подобно функциям
классы можно определять по синтаксису Class Expression в следующем виде:
let Book = class {
constructor(title, author, price) {
this.title = title;
this.author = author;
this.price = price;
};
}
Причем,
использовать класс можно только после его объявления как бы он ни был объявлен.
В отличие от функций, которые можно вызывать в скрипте до их определения, если
они заданы по синтаксису Function Declaration.
Также, подобно
функциям, классам можно назначать имя при следующем определении:
let Book = class BookClass {
constructor(title, author, price) {
this.title = title;
this.author = author;
this.price = price;
};
}
Причем, это
второе имя будет видно только внутри этого класса. За его пределами можно
обращаться только через переменную Book.
Интересной
особенностью является возможность создавать классы динамически с помощью
функции, например, так:
function createFruit(name, weight) {
return class {
constructor() {
this.name = name;
this.weight = weight;
};
showInfo() { console.log(this.name + " " + this.weight) };
}
}
Здесь описана
функция, которая формирует новый класс со значениями параметров name и weight, которые будут
записаны в объект при его создании. Далее, мы можем создать класс для
определенного фрукта:
let f1 = createFruit("Яблоко", 100);
Причем, здесь f1 – это ссылка
на класс, а не на созданный объект, то есть, далее, нужно вызвать оператор new и создать
объект:
let apple = new f1();
apple.showInfo();
Если вызвать
функцию еще раз с другими параметрами:
let f2 = createFruit("Вишня", 40);
то будет создан
еще один класс, никак не связанный с предыдущим и, далее, также можно выполнить
следующие конструкции:
let v = new f2();
v.showInfo();
То есть, все
классы работают совершенно независимо.
Геттеры и сеттеры классов
Часто в классах
прописывают специальные методы:
-
геттеры
– для получения свойств объекта;
-
сеттеры
– для изменения свойств объекта.
В рамках JavaScript такие методы
можно объявлять с помощью специальных ключевых слов:
get и set
следующим
образом:
get titleBook() {return this.title; }
set titleBook(value) { this.title = value; }
И, далее,
использовать, просто обращаясь к ним по имени:
let book1 = new Book("Муму", "Тургенев", 112);
console.log( book1.titleBook );
book1.titleBook = "Мы болеем за Муму";
console.log( book1.titleBook );
Это бывает очень
удобно.
Свойства классов
Совсем недавно
была добавлена возможность описания свойств непосредственно внутри класса,
например, так:
class Book {
pages = 123;
constructor(title, author, price) {
this.title = title;
this.author = author;
this.price = price;
};
}
Причем, они
автоматически становятся частью самого объекта book1, а не базового
класса. Мы в этом можем легко убедиться, если выведем объект в консоль:
Вот что из себя
представляют классы в базовом представлении.