new
Оператор new
дає розробникам змогу створювати примірники самотужки визначених об'єктних типів, а також вбудованих об'єктних типів, котрі мають функцію-конструктор.
Спробуйте його в дії
Синтаксис
new constructor
new constructor()
new constructor(arg1)
new constructor(arg1, arg2)
new constructor(arg1, arg2, /* …, */ argN)
Параметри
constructor
Клас чи функція, що задає тип примірника об'єкта. Цей вираз може бути чим завгодно, що має достатній пріоритет, включно з ідентифікатором, звертанням до властивості чи ще одним виразом
new
, проте необов'язкові ланцюжки тут заборонені.arg1
,arg2
, …,argN
Список значень, з якими буде викликаний
constructor
. Записnew Foo
– рівносильнийnew Foo()
, тобто якщо список аргументів не заданий, тоFoo
викликається без аргументів.
Опис
Коли функція викликається з ключовим словом new
, то ця функція використовується як конструктор. new
виконає наступні дії:
-
Створить чистенький простий об'єкт JavaScript. Заради зручності, назвімо його
newInstance
. -
Спрямовує комірку [[Prototype]] об'єкта
newInstance
на значення властивостіprototype
функції-конструктора, якщо це значення єоб'єктом
. Інакше –newInstance
залишається простим об'єктом, зі значеннямObject.prototype
у комірці [[Prototype]].Примітка: Властивості й об'єкти, додані до властивості
prototype
функції-конструктора, таким чином, доступні всім примірникам, створені на основі цієї функції-конструктора. -
Виконує функцію-конструктор із заданими аргументами, зв'язуючи
newInstance
як контекстthis
(тобто всі посилання наthis
у функції-конструкторі, відтак, вказуватимуть наnewInstance
). -
Якщо функція-конструктор повертає непримітивне значення, то таке повернене значення стає результатом усього виразу
new
. Інакше, якщо функція-конструктор не повертає нічого або повертає примітив, то замість цього повертаєтьсяnewInstance
. (Здебільшого конструктори не повертають значень, але можуть вирішити повернути, щоб перевизначити звичайний процес створення об'єкта.)
Примірник класу можна створити лише за допомогою оператора new
– спроба викликати клас без new
викине TypeError
.
Створення об'єкта зі власною функцією-конструктором вимагає двох кроків:
-
Означення типу об'єкта, шляхом написання функції, що задає його назву та властивості. Наприклад, функція-конструктор для створення об'єкта
Foo
могла б мати такий вигляд:function Foo(bar1, bar2) { this.bar1 = bar1; this.bar2 = bar2; }
-
Створення примірника об'єкта за допомогою
new
.const myFoo = new Foo("Bar 1", 2021);
Примітка: Об'єкти можуть мати властивості, котрі самі є іншими об'єктами. Приклади цього – нижче.
До раніше означного примірника об'єкта завжди можна додати властивість. Наприклад, інструкція car1.color = "black"
додає властивість color
до car1
, а тоді присвоює їй значення "black"
.
Проте це не впливає на жодні інші об'єкти. Аби додати нову властивість до всіх об'єктів певного типу, необхідно додати цю властивість до властивості prototype
конструктора. Це означить властивість, котра є спільною для всіх об'єктів, створених за допомогою цієї функції, а не лише для одного примірника об'єктного типу. Наступний код додає всім об'єктам типу Car
властивість color
зі значенням "original color"
, а тоді перезаписує це значення рядком "black"
, але лише на об'єкті-примірнику car1
. Докладніше про це – на сторінці прототипів.
function Car() {}
const car1 = new Car();
const car2 = new Car();
console.log(car1.color); // undefined
Car.prototype.color = "original color";
console.log(car1.color); // 'original color'
car1.color = "black";
console.log(car1.color); // 'black'
console.log(Object.getPrototypeOf(car1).color); // 'original color'
console.log(Object.getPrototypeOf(car2).color); // 'original color'
console.log(car1.color); // 'black'
console.log(car2.color); // 'original color'
Примітка: Попри те, що функція-конструктор може бути викликана так, як будь-яка звичайна функція (тобто без оператора
new
operator), в такому випадку новий об'єкт не створюється, і значенняthis
– також буде іншим.
Функція може дізнатися, чи була вона викликана з new
, шляхом перевірки new.target
. new.target
має значення undefined
лише тоді, коли функція закликана без new
. Наприклад, можна мати функцію, що поводиться по-різному, коли вона викликана і коли конструюється:
function Car(color) {
if (!new.target) {
// Викликана як функція.
return `${color} car`;
}
// Викликана з new.
this.color = color;
}
const a = Car("red"); // a має значення "red car"
const b = new Car("red"); // b має значення `Car { color: "red" }`
До стандарту ES6, котрий запровадив класи, більшість вбудованих об'єктних типів JavaScript можна було створювати і з, і без new
, хоч чимало з них при цьому поводиться по-різному. Кілька прикладів:
Array()
,Error()
іFunction()
поводяться однаково і бувши викликаними як функція, і як конструктор.Boolean()
,Number()
іString()
, бувши викликаними, зводять свій аргумент до відповідного примітивного типу, а коли конструюються – повертають об'єкти-обгортки.Date()
повертає рядок, що представляє поточну дату, бувши викликаною, що рівносильноnew Date().toString()
.
Згідно зі стандартом ES6, мова стала суворішою щодо того, що є конструктором, а що – функцією. Наприклад:
Symbol()
іBigInt()
можна викликати лише безnew
. Спроба конструювати їх – викинеTypeError
.Proxy
іMap
можуть бути сконструйовані лише зіnew
. Спроба викликати їх – викинеTypeError
.
Приклади
Об'єктні типи та примірники об'єктів
Припустімо, що розробляється об'єктний тип для автівок. Цей тип об'єктів повинен зватися Car
, і мати властивості з маркою, моделлю та роком виробництва. Щоб цього досягнути, варто написати наступну функцію:
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
Тепер об'єкт на ймення myCar
можна створити так:
const myCar = new Car("Eagle", "Talon TSi", 1993);
Ця інструкція створює myCar
і присвоює їй задані значення властивостей. Далі значенням myCar.make
є рядок "Eagle", myCar.year
– ціле число 1993, і так далі.
Шляхом викликів new
можна створити будь-яке число об'єктів car
.
const kensCar = new Car("Nissan", "300ZX", 1992);
Властивість об'єкта, котра сама є іншим об'єктом
Припустімо, що означується об'єкт, названий Person
, отак:
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
А потім створюються два нові об'єкти Person
, отак:
const rand = new Person("Rand McNally", 33, "M");
const ken = new Person("Ken Jones", 39, "M");
Далі можна переписати означення Car
, аби додати властивість owner
, котра приймає об'єкт Person
, отак:
function Car(make, model, year, owner) {
this.make = make;
this.model = model;
this.year = year;
this.owner = owner;
}
Щоб створювати нові об'єкти, можна використовувати наступне:
const car1 = new Car("Eagle", "Talon TSi", 1993, rand);
const car2 = new Car("Nissan", "300ZX", 1992, ken);
Замість передавання при створенні нових об'єктів рядків-літералів чи цілих чисел, інструкції вище передають за параметр власника об'єкти rand
і ken
. Аби з'ясувати ім'я власника car2
, можна звернутися до наступної властивості:
car2.owner.name;
Використання new
вкупі з класами
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Привіт, моє ім'я – ${this.name}`);
}
}
const p = new Person("Кароліна");
p.greet(); // Привіт, моє ім'я – Кароліна
Специфікації
Сумісність із браузерами
desktop | mobile | server | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
new
|
Chrome Full support 1 | Edge Full support 12 | Firefox Full support 1 | Internet Explorer Full support 3 | Opera Full support 3 | Safari Full support 1 | WebView Android Full support 1 | Chrome Android Full support 18 | Firefox for Android Full support 4 | Opera Android Full support 10.1 | Safari on iOS Full support 1 | Samsung Internet Full support 1.0 | Deno Full support 1.0 | Node.js Full support 0.10.0 |