Классы и наследование в ES5
Т.к. в ES5 классов - нет, объекты создаются с помощью простых функций. Эти функции называются конструкторами. Основное отличие конструкторов от простых функций:
function Task(title){
this._title = title;
this._done = false;
Task.count += 1;
}
В ES5 свойства создаются при помощи метода defineProperty у объекта Object. Метод Object.defineProperty() определяет новое или изменяет существующее свойство непосредственно на объекте, возвращая этот объект. Подробнее: MDN, learn.javascript.ru.
Object.defineProperty(Task, 'title', {
get: function () {
return this._title;
},
set: function (value) {
this._title = value;
}
});
В ES5 для создания метода класса - он указывается на прототипе prototype функции конструктора. Это делается для того чтобы не создавать метод на экземпляре объекта, т.к. если мы в конструкторе укажем this.complete - то каждый экземпляр класса Task будет иметь отдельный метод. Т.е. он реально будет занимать место в памяти. Если же мы укажем метод на прототипе объекта то все объекты будут ссылаться на один и тот же метод.
Task.prototype.complete = function () {
this._done = true;
};
Статические методы указываются на самом классе и доступ к ним через сам класс. В JS всё вляется объектом включая функции, поэтому мы можем присвоить функции Task - свойство, значением которого будет функция.
Task.getDefaultTitle = function () {
return 'Задача';
}
Статические свойства объявляются на самом классе за пределами класса.
Task.count = 0;
Наследование: В ES5 для того чтобы правильно инициализтировать объект - необходимо вызвать конструктор родительского класса. Это делается с помощью метода call на функции конструкторе, в которую мы отправляем создаваемый объект, ссылка на который хранится в слове this и параметры необходимые для правильной инициализации. У каждой функции есть метод call, который позволяет вызвать функцию и при этом указать значение this (контекста) для этой функции. После того как конструктор ролительского класса вернёт нам объект мы присвоим ему свойства parent.
function SubTask(title, parent) {
Task.call(this, title);
this._parent = parent;
}
Для правильного определения наследования необходимо использовать прототип.
Метод Object.create()
создаёт новый объект с указанными объектом прототипа и свойствами. Подробнеее: MDN, Прототип объекта[learn.javascript.ru].
// Мы указываем что прототипом класса SubTask является прототип класса Task.
SubTask.prototype = Object.create(Task.prototype);
// Указываем что у прототипа класса SubTask конструктором является функция SubTask.
SubTask.prototype.constructor = SubTask;
Итоговый класс
function Task(title){
this._title = title;
this._done = false;
Task.count += 1;
}
Object.defineProperty(Task, 'title', {
get: function () {
return this._title;
},
set: function (value) {
this._title = value;
}
});
Task.prototype.complete = function () {
this._done = true;
};
Task.getDefaultTitle = function () {
return 'Задача';
}
function SubTask(title, parent) {
Task.call(this, title);
this._parent = parent;
}
SubTask.prototype = Object.create(Task.prototype);
SubTask.prototype.constructor = SubTask;
var task = new Task('Изучить JavaScript');
var subtask = new SubTask('Изучить ES6', task);
console.log(task);
console.log(subtask);