В этом руководстве вы узнаете о функции-конструкторе в JavaScript и как использовать ключевое слово new для создания объекта.
В руководстве по объектам JavaScript вы узнали, как использовать синтаксис литерала для создания нового объекта.
Например, в следующем примере создается новый объект person с двумя свойствами firstName и lastName :
let person = {
firstName: 'John',
lastName: 'Doe'
};На практике вам часто нужно создать много подобных объектов, таких как объект person.
Для этого вы можете использовать функцию конструктор для определения пользовательского типа и оператор new для создания нескольких объектов из этого типа.
С технической точки зрения функция-конструктор — это обычная функция со следующим соглашением:
- Имя функции-конструктора начинается с заглавной буквы, например,
Person,Documentи т. д. - Функция-конструктор должна вызываться только с оператором
new.
Обратите внимание, что ES6 вводит ключевое слово class, которое позволяет вам определять пользовательский тип. А классы — это просто синтаксический сахар над функциями-конструкторами с некоторыми улучшениями.
В следующем примере определяется функция-конструктор с именем Person :
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}В этом примере Person такая же, как и обычная функция, за исключением того, что ее имя начинается с заглавной буквы P
Чтобы создать новый экземпляр Person, вы используете new оператор:
let person = new Person('John','Doe');По сути, new оператор делает следующее:
- Создает новый пустой объект и назначает его переменной
this. - Назначает аргументы
'John'и'Doe'свойствамfirstNameиlastNameобъекта. - Возвращает
thisзначение.
Это функционально эквивалентно следующему:
function Person(firstName, lastName) {
// this = {};
// add properties to this
this.firstName = firstName;
this.lastName = lastName;
// return this;
}Следующее утверждение:
let person = new Person('John','Doe');… возвращает тот же результат, что и следующий оператор:
let person = {
firstName: 'John',
lastName: 'Doe'
};Однако функция-конструктор Person позволяет создавать несколько похожих объектов. Например:
let person1 = new Person('Jane','Doe')
let person2 = new Person('James','Smith')Добавление методов
Объект может иметь методы, которые манипулируют его данными. Чтобы добавить метод к объекту, созданному с помощью функции-конструктора, вы можете использовать ключевое слово this. Например:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.getFullName = function() {
return this.firstName + " " + this.lastName;
};
}Теперь вы можете создать новый объект Person и вызвать метод getFullName() :
let person = new Person("John", "Doe");
console.log(person.getFullName());Выход:
John Doe
Проблема с функцией конструктора заключается в том, что когда вы создаете несколько экземпляров Person, this.getFullName() дублируется в каждом экземпляре, что неэффективно с точки зрения использования памяти.
Чтобы решить эту проблему, вы можете использовать прототип, чтобы все экземпляры пользовательского типа могли использовать одни и те же методы.
Возврат из функций-конструкторов
Как правило, функция-конструктор неявно возвращает this значение для вновь созданного объекта. Но если у него есть оператор return, то вот правила:
- Если
returnвызывается с объектом, функция-конструктор возвращает этот объект вместоthis. - Если
returnвызывается со значением, отличным от объекта, он игнорируется.
Вызов без new ключевого слова
Технически вы можете вызывать функцию-конструктор как обычную функцию, не используя ключевое слово new, например:
let person = Person('John','Doe');В этом случае Person просто выполняется как обычная функция. Следовательно, this внутри функции Person привязывается не к переменной person, а к глобальному объекту.
Если вы попытаетесь получить доступ к свойству firstName или lastName, вы получите сообщение об ошибке:
console.log(person.firstName);
Ошибка:
TypeError: Cannot read property 'firstName' of undefined
Точно так же вы не можете получить доступ к getFullName(), поскольку он привязан к глобальному объекту.
person.getFullName();
Ошибка:
TypeError: Cannot read property 'getFullName' of undefined
Чтобы предотвратить вызов функции конструктора без ключевого слова new, в ES6 было введено свойство new.target.
Если функция-конструктор вызывается с ключевым словом new, new.target возвращает ссылку на функцию. В противном случае он возвращает undefined.
Следующее добавляет оператор внутри функции Person, чтобы показать new.target на консоли:
function Person(firstName, lastName) {
console.log(new.target);
this.firstName = firstName;
this.lastName = lastName;
this.getFullName = function() {
return this.firstName + " " + this.lastName;
};
}Следующее возвращает undefined, потому что функция-конструктор Person вызывается как обычная функция:
let person = Person("John", "Doe");Выход:
undefined
Однако следующий код возвращает ссылку на функцию Person, поскольку она вызывается с ключевым словом new :
let person = new Person("John", "Doe");Выход:
[Function: Person]
Используя new.target, вы можете заставить вызывающие функции конструктора использовать new ключевое слово. В противном случае вам может выдать такую ошибку:
function Person(firstName, lastName) {
if (!new.target) {
throw Error("Cannot be called without the new keyword");
}
this.firstName = firstName;
this.lastName = lastName;
}Кроме того, вы можете сделать синтаксис более гибким, создав новый объект Person, если пользователи функции-конструктора не используют ключевое слово new :
function Person(firstName, lastName) {
if (!new.target) {
return new Person(firstName, lastName);
}
this.firstName = firstName;
this.lastName = lastName;
}
let person = Person("John", "Doe");
console.log(person.firstName);Этот шаблон часто используется в библиотеках и фреймворках JavaScript, чтобы сделать синтаксис более гибким.
