> For the complete documentation index, see [llms.txt](https://strctr.gitbook.io/programming/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://strctr.gitbook.io/programming/01-languages/javascript/01-language/c-functions/c2-constructors/01-constructor-function.md).

# 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`, который будет отброшен.

```javascript
// функция-конструктор
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`.

```javascript
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`-объекта конструктора, или метод прототипа.

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

* *Статический метод* - метод функции-конструктора.
* *Статическое поле* - атрибут функции конструктора.

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

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