Конструкторы

1. Конструкторы

Обычный синтаксис литерала объекта {} позволяет создать один объект. Но зачастую нужно создать много однотипных объектов динамически во время выполнения программы. Для этого используют функции-конструкторы, вызывая их при помощи специального оператора new.

Конструктор — это обычная функция, к которой применили оператор new. Это приводит к созданию нового объекта и вызову функции в контексте этого объекта.

Чтобы отличить конструктор от обычной функции, конструкторы принято называть с большой буквы, а в самом названии отражать тип создаваемого объекта. Мы уже работали с конструкторами встроенными в язык: Object, Array, Number, String и другие.

Процесс создания объекта через конструктор происходит следующим образом:

  • Создаётся новый пустой объект.

  • Функция-конструктор вызывается в контексте этого объекта.

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

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

  • Возвращается this.

const Hotel = function (name, stars, capacity) {
  this.name = name;
  this.stars = stars;
  this.capacity = capacity;
};

// В результате вызова
const hotel = new Hotel('Resort Hotel', 5, 100);
// Получаем такой объект
console.log(hotel);
// Hotel {name: "Resort Hotel", stars: 5, capacity: 100}
Copy

Если визуализировать происходящее, то при вызове new Hotel происходит следующее (первая и последняя строка — это то, что делает интерпретатор).

const Hotel = function (name, stars, capacity) {
  // this = {};

  // в this пишем свойства и методы
  this.name = name;
  this.stars = stars;
  this.capacity = capacity;

  // return this;
};
Copy

Теперь многократными вызовами new Hotel с разными аргументами мы можем создать любое количество объектов. Использование конструкторов удобно при создании множества объектов с одним набором свойств, имеющих разные значения. Поэтому такую функцию и называют конструктором — она предназначена для конструирования объектов по заранее подготовленному шаблону.

const Hotel = function (name, stars, capacity) {
  this.name = name;
  this.stars = stars;
  this.capacity = capacity;
};

const hotel = new Hotel('Resort Hotel', 5, 100);
console.log(hotel);
// Hotel {name: "Resort Hotel", stars: 5, capacity: 100}

const motel = new Hotel('Sunlight Motel', 4, 300);
console.log(motel);
// Hotel {name: "Sunlight Motel", stars: 4, capacity: 300}
Copy

2. Внутренние методы [[Call]] и [[Construct]]

Функции вызываются используя два разных внутренних метода: [[Call]] и [[Construct]].

  • Когда функция вызывается без new, выполняется метод [[Call]], который исполняет тело функции так, как оно описано в коде.

  • Когда функция вызывается с new, выполняется метод [[Construct]], который отвечает за создание нового объекта и исполнения тела функции с this, ссылающимся на этот объект.

Не все функции имеют внутренний метод [[Construct]] и поэтому не все функции могут быть вызваны через new. Стрелочные функции не имеют метода [[Construct]] и поэтому не могут быть использованы в качестве конструкторов.

3. Добавление методов

Использование функций для создания объекта дает большую гибкость. Можно передавать конструктору параметры, определяющие как его создавать и он будет создавать объекты заданным образом.

Добавим метод в создаваемый объект. Например, пусть Hotel имеет методы для приветствия гостя и добавления и удаления количества гостей в поле guestCount. Проверки на вместительность пропустим.

const Hotel = function (name, stars, capacity) {
  this.name = name;
  this.stars = stars;
  this.capacity = capacity;
  this.guestCount = 0;

  this.greet = function (guestName) {
    console.log(`Hello ${guestName}, wellcome to ${this.name}`);
  };

  this.addGuests = function (amount) {
    this.guestCount += amount;
  };

  this.removeGuests = function (amount) {
    this.guestCount -= amount;
  };
};

const hotel = new Hotel('Sunrise Hotel', 5, 100);

console.log(hotel);
// Hotel {name: "Sunrise Hotel", greet: ƒ, addGuests: f, removeGuests: f}
hotel.greet('Mango'); // Hello Mango, wellcome to Sunrise Hotel
hotel.addGuests(50);
hotel.removeGuests(50);
Copy

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

4. Управляем магазином

Время практики. Представьте, что у нас есть магазин и два менеджера, по продаже товаров. Необходимо написать логику для организации их работы. Для каждого менеджера создаётся отдельный объект.

const mango = {
  name: 'Mango',
  sales: 5,
  sell(product) {
    this.sales += 1;
    return `Manager ${this.name} sold ${product}.`;
  },
};

console.log(mango.sales); // 5
console.log(mango.sell('TV')); // Manager Mango sold TV
console.log(mango.sell('Microwave')); // Manager Mango sold Microwave
console.log(mango.sales); // 7

const poly = {
  name: 'Poly',
  sales: 10,
  sell(product) {
    this.sales += 1;
    return `Manager ${this.name} sold ${product}.`;
  },
};

console.log(poly.sales); // 10
console.log(poly.sell('TV')); // Manager Poly sold TV
console.log(poly.sell('Microwave')); // Manager Poly sold Microwave
console.log(poly.sales); // 12
Copy

Это было просто и всё работает хорошо, но мы буквально захардкодили менеджеров заранее. Представьте что будет, когда наш магазин вырастет и пополнится парой сотен менеджеров, для каждого из которых будет необходимо создать объект динамически во время выполнения программы. Очевидно, что создавать объекты подобным способом — не самая лучшая затея. К счастью, мы знаем о конструкторах.

const Manager = function (name = 'manager', sales = 0) {
  this.name = name;
  this.sales = sales;

  this.sell = function (product) {
    this.sales += 1;
    return `Manager ${this.name} sold ${product}.`;
  };
};

const mango = new Manager('Mango', 5);
console.log(mango.sales); // 5
console.log(mango.sell('TV')); // Manager Mango sold TV
console.log(mango.sell('Microwave')); // Manager Mango sold Microwave
console.log(mango.sales); // 7

const poly = new Manager('Poly', 10);
console.log(poly.sales); // 10
console.log(poly.sell('TV')); // Manager Poly sold TV
console.log(poly.sell('Microwave')); // Manager Poly sold Microwave
console.log(poly.sales); // 12
Copy

Теперь, когда мы узнаем как работать с HTML-документом, нам не страшно любое количество менеджеров. Собрав поля из форм регистрации, можно динамически создавать объекты по введенной информации.

Last updated