01. Constructor Function

Функции, вызываемые с оператором new, называются конструкторами. Конструкторы работают как фабрика для создания "похожих" объектов. Каждый конструктор определяет класс объектов --- это множество объектов, создаваемых при помощи этого конструктора.

Технически, конструктором становится любая функция, вызванная через new. Любая функция может быть использована как конструктор. То есть, любую функцию можно вызвать при помощи new. Как-то особым образом указывать, что она — конструктор — не надо.

Функции-конструкторы имеют специальное свойство prototype, которое автоматически становится прототипом для создаваемых объектов. В prototype можно описать атрибуты и методы, которые будут у всех объектов, создаваемых при помощи этой функции-конструктора.

Основные особенности:

  • Функции-конструкторы по соглашению обязаны именоваться с заглавной буквы CamelCase.

  • Должны вызываться вместе с new.

  • Должны возвращать новый экземпляр объекта с определенными свойствами, отражающего его принадлежность к классу конструктора.

Usage

Процесс определения класса в языке JavaScript можно свести к трем этапам.

  1. Написать функцию-конструктор, которая будет определять свойства экземпляра в новом объекте.

  2. Определить методы экземпляров в объекте-прототипе конструктора.

  3. Определить поля класса и свойства класса в самом конструкторе.

Алгоритм работы функции-конструктора Constructor, запущенной через new Constructor():

  • Автоматически создается новый пустой объект, с прототипом установленным в Constructor.prototype.

  • Ключевое слово this внутри функции-конструктора получает ссылку на этот объект.

  • Функция выполняется. Как правило, она модифицирует this, добавляет методы, свойства.

  • Возвращается this (явный return указывать не нужно). Как правило, конструкторы ничего не возвращают. Их задача — записать всё, что нужно, в this, который автоматически станет результатом.

  • Если явный вызов return всё же есть, то будет возвращён явный объект, а не this, который будет отброшен.

// функция-конструктор
function Foo(y) {
  // которая умеет создавать объекты
  // по заданному шаблону: все эти объекты
  // будут иметь родное свойство "y"
  this.y = y;
}

// также "Foo.prototype" хранит ссылку
// на прототип вновь создаваемых объектов,
// поэтому мы можем использовать эту ссылку
// для созданиях наследуемых или разделяемых
// свойств; так же как и в предыдущем случае мы имеем:

// унаследованное свойство "x"
Foo.prototype.x = 10;

// и унаследованный метод"calculate"
Foo.prototype.calculate = function(z) {
  return this.x + this.y + z;
};

// создаём наши объекты "b" и "c"
// используя "шаблон" Foo
var b = new Foo(20);
var c = new Foo(30);

// вызываем унаследованный метод
b.calculate(30); // 60
c.calculate(40); // 80

// покажем, что мы работаем именно
// с теми свойствами, которые ожидаем

b.__proto__ === Foo.prototype, // true
  c.__proto__ === Foo.prototype, // true
  // также "Foo.prototype" автоматически создает
  // специальное свойство "constructor", являющееся
  // ссылкой на саму функцию-конструктор, т.е. на "Foo";
  // объекты "b" и "c" могут найти это свойство посредством
  // делегации и использовать его для проверки своего конструктора

  b.constructor === Foo, // true
  c.constructor === Foo, // true
  Foo.prototype.constructor === Foo, // true
  b.calculate === b.__proto__.calculate, // true
  b.__proto__.calculate === Foo.prototype.calculate; // true

Объект считается корректно созданным функцией-конструктором, если он обладает следующими особенностями:

  • В поле obj.constructor === Constructor будет находится ссылка на его функцию-конструктор.

  • В прототип объекта записывается значение Constructor.prototype, а именно Object.setPrototypeOf(this, Constructor.prototype).

  • Оператор obj instanceof Constructor будет возвращать true.

  • Для системных объектов справедливо, что Object.prototype.toString(obj) вернет специальную строку с классом объекта.

Return

Функция-конструктор может не иметь явного return в конце, хотя иметь один или несколько return конструктору не запрещено. Если в функции нет return, то в этом случае неявно возвращается создаваемый объект (this). Если же функция имеет return, то создаваемый объект отбрасывается и возвращается результат оператора return.

function Article(content) {
  if (content.isEmpty()) {
    return Article.EMPTY_CONTENT;
  }
  this.count = Article.count;
  this.format = Article.DEFAULT_FORMAT;
  this.content = content;
}

Static fields and instance fields

Избегайте хранить данные в прототипе конструктора. Не разделяйте между создаваемыми объектами в конструкторе начальные данные. Каждый создаваемый объект должен иметь свою копию начальных данных.

  • Поле класса - свойство this-объекта конструктора, или свойство прототипа.

  • Метод класса - метод this-объекта конструктора, или метод прототипа.

Методы и свойства, которые не привязаны к конкретному экземпляру объекта, называют «статическими». Если нужны глобальные данные, разделяемые между всеми экземплярами класса, то их записывают прямо в саму функцию-конструктор.

  • Статический метод - метод функции-конструктора.

  • Статическое поле - атрибут функции конструктора.

function Article(content) {
  this.count = Article.count;
  this.format = Article.DEFAULT_FORMAT;
  this.content = content;
}

Article.count = 0; // статическое свойство-переменная
Article.DEFAULT_FORMAT = "html"; // статическое свойство-константа

Last updated