Что такое фабричные функции и конструкторы?

0 Акции
0
0
0
0

Введение

Чтобы понять концепцию фабричных функций и конструкторов, необходимо сначала понять функции и объекты.

Если вы создаёте много объектов со схожими свойствами и функциями, это может стать скучным и однообразным. Мы хотим помнить о принципе DRY code (не повторяйся). Существуют функциональные шаблоны, которые помогут нам писать более короткий, понятный и эффективный код. Фабричные функции и функции-конструкторы могут справиться с этой задачей, но какой из них следует использовать? Давайте немного подробнее рассмотрим, что такое фабричные функции и конструкторы, что они могут и не могут делать, а также в чём их сходства и различия.

Что такое фабричная функция?

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

const car1 = {
make: 'Toyota',
model: 'Tacoma',
year: 2018,
fuelType: 'gas', 
bodyType: 'mid-size pick-up truck',
getFullName() {
return `${this.year} ${this.make} ${this.model}`;
}
}
console.log(car1.getFullName()); // => 2018 Toyota Tacoma

В приведённом выше примере мы создаём объект, описывающий конкретную машину. Теперь давайте создадим объект, аналогичный этому.

const car2 = {
make: 'Tesla', 
model: 'Model S',
year: 2018,
fuelType: 'electric',
bodyType: 'sedan',
getFullName() {
return `${this.year} ${this.make} ${this.model}`;
}
}
console.log(car2.getFullName()); // => 2018 Tesla Model S 

Я мог бы долго рассказывать о создании новых машинных объектов, но у кого есть на это время, верно? Давайте посмотрим, как это работает в качестве фабричной функции.

function createCar (make, model, year, fuelType, bodyType) {
return {
make: make, 
model: model, 
year: year, 
fuelType: fuelType, 
bodyType: bodyType,
getFullName() {
return `${year} ${make} ${model}`;
}
}
}

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

function createCar (make, model, year, fuelType, bodyType) {
return {
make: make, 
model: model, 
year: year, 
fuelType: fuelType, 
bodyType: bodyType,
getFullName() {
return `${year} ${make} ${model}`;
}
}
}
const car1 = createCar('Toyota', 'Tacoma', 2018, 'gas', 'mid-size pick-up truck');
const car2 = createCar('Tesla', 'Model S', 2018, 'electric', 'sedan');
console.log(car1.getFullName()); // => 2018 Toyota Tacoma
console.log(car2.getFullName()); // => 2018 Tesla Model S

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

Что такое конструкторы?

Функция-конструктор — это ещё один шаблон JavaScript, очень похожий на фабричные функции. Однако, в отличие от фабричных функций, функции-конструкторы фактически не возвращают объект. Чтобы создать разные объекты с одинаковыми свойствами, нужно использовать ключевые слова new и this. Итак, давайте посмотрим, как работают функции-конструкторы визуально.

function Car(make, model, year, fuelType, bodyType) {
this.make = make
this.model = model 
this.year = year
this.fuelType = fuelType
this.bodyType = bodyType
this.getFullName = () => {
return `${this.year} ${this.make} ${this.model}`;
}
}

В приведённом выше примере функция-конструктор очень похожа на фабричную функцию, за исключением использования ключевого слова “this”. ”this” относится к функции-конструктору, создавшей экземпляр объекта. Другими словами, “this” не имеет значения в функции-конструкторе. Вы можете рассматривать её как основу для нового объекта.

function Car(make, model, year, fuelType, bodyType) {
this.make = make
this.model = model 
this.year = year
this.fuelType = fuelType
this.bodyType = bodyType
this.getFullName = () => {
return `${this.year} ${this.make} ${this.model}`;
}
}
const car1 = new car('Toyota', 'Tacoma', 2018, 'gas', 'mid-size pick-up truck');
const car2 = new car('Tesla', 'Model S', 2018, 'electric', 'sedan');
console.log(car1.getFullName()); // => 2018 Toyota Tacoma
console.log(car2.getFullName()); // => 2018 Tesla Model S

Для создания объектов с помощью функций-конструкторов мы используем ещё одно ключевое слово — “new”. Когда вы используете оператор “new” перед вызовом функции, JavaScript автоматически выполняет две операции: внутри функции создаёт пустой объект с именем “this”. Он возвращает объект “this” оператору, который изначально вызвал функцию.

function Car(make, model, year, fuelType, bodyType) {
// const this = {};
this.make = make
this.model = model 
this.year = year
this.fuelType = fuelType
this.bodyType = bodyType
this.getFullName = () => {
return `${this.year} ${this.make} ${this.model}`;
}
// return this;
}
const car1 = new car('Toyota', 'Tacoma', 2018, 'gas', 'mid-size pick-up truck');
const car2 = new car('Tesla', 'Model S', 2018, 'electric', 'sedan');
console.log(car1.getFullName()); // => 2018 Toyota Tacoma
console.log(car2.getFullName()); // => 2018 Tesla Model S

Наследование

Наследование играет важную роль в различии между функциями фабрики и строителя.

function createCar (make, model, year, fuelType, bodyType) {
return {
make: make, 
model: model, 
year: year, 
fuelType: fuelType, 
bodyType: bodyType,
getFullName() {
return `${year} ${make} ${model}`;
}
}
}
const car1 = createCar('Toyota', 'Tacoma', 2018, 'gas', 'mid-size pick-up truck');
const car2 = createCar('Tesla', 'Model S', 2018, 'electric', 'sedan'); 
car1.getFullName = function() {
return `My ${fuelType} ${bodyType} is a ${year} ${make} ${model}`;
}
console.log(car1.getFullName()); // => My gas mid-size pick-up truck is a 2018 Toyota Tacoma
console.log(car2.getFullName()); // => 2018 Tesla Model S

Вернёмся к первому примеру фабричной функции. Что, если мы захотим переобъявить car1.getFullName()? Дело в том, что car1.getFullName() и car2.getFullName() — это не одна и та же функция в памяти. Каждый объект получает свою копию функции. Это означает, что когда функция создаёт объект и возвращает его, она копирует свойства и значения и привязывает их к каждому объекту, вызывающему эту функцию.

function car(make, model, year, fuelType, bodyType) {
// const this = {};
this.make = make
this.model = model 
this.year = year
this.fuelType = fuelType
this.bodyType = bodyType
this.getFullName = () => {
return `${this.year} ${this.make} ${this.model}`;
}
// return this;
}
const car1 = new car('Toyota', 'Tacoma', 2018, 'gas', 'mid-size pick-up truck');
const car2 = new car('Tesla', 'Model S', 2018, 'electric', 'sedan');
console.log(car1); // => car {make: 'Toyota', model: 'Tacoma' , etc.}

Теперь давайте взглянем на нашу функцию-конструктор, представленную выше. При создании конструктора у него есть собственный прототип. Когда мы создаём новый объект Car с помощью ключевого слова new, создаётся экземпляр типа Car. Другими словами, прототип car1 имеет тип Car. Теперь car1 наследует конструктор Car. Это позволяет нам добавлять свойства к прототипу Car.

Car.prototype.sentence = function() {
return `My ${this.fuelType} ${this.bodyType} is a ${this.year} ${this.make} ${this.model}`;
}
console.log(car1); // => Car {
// make: 'Toyota',
// model: 'Tacoma',
// year: 2018,
// fuelType: 'gas',
// bodyType: 'mid-size pick-up truck',
// getFullName: [Function (anonymous)]
// }

Обратите внимание, что функция предложения не добавляется непосредственно в конструктор автомобилей.

console.log(Car.prototype); // => { sentence: [Function (anonymous)] }

Но когда мы проверяем его прототип, то видим его! Теперь мы можем получить доступ к новой добавленной функции.

console.log(car1.sentence()); // => My gas mid-size pick-up truck is a 2018 Toyota Tacoma
console.log(car2.sentence()); // => My electric sedan is a 2018 Tesla Model S

Теперь, когда мы знаем, как работает каждая операция, возникает вопрос: какую из них использовать? Оба дают одинаковый результат. Конструкторы отлично подходят для добавления или удаления свойства любого объекта, унаследованного от конструктора. Однако фабричные функции проще понять, поскольку, в конечном счёте, это всего лишь функция. Для фабричных функций нет необходимости вводить ключевое слово “new”. Благодаря замыканиям это может быть более гибким. С их помощью можно реализовать так называемую “конфиденциальность данных”. Давайте рассмотрим другой пример, объясняющий, как это работает.

function createCar(make, model, year) {
return {
getFullName() {
return `${year} ${make} ${model}`;
}
}
}
const car1 = createCar('Toyota', 'Tacoma', 2018); 
console.log(car1.getFullName()); // => 2018 Toyota Tacoma
console.log(car1.make); // => undefined
console.log(car1); // => { getFullName: [Function: getFullName] }

Результат

В целом, при написании собственного кода важно, чтобы в нём не было ничего неправильного. Есть хороший способ сделать код понятным и коротким. Используйте фабричные функции и функции-конструкторы там, где это наиболее целесообразно.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Вам также может понравиться