05. Enforce new
Существует серьёзная опасность, связанная с конструктором функций: если при вызове конструктора функций отсутствует ключевое слово new
, то this
связывается не с создаваемым объектом, а с глобальным объектом.
function Vehicle(type, wheelsCount) {
this.type = type;
this.wheelsCount = wheelsCount;
return this;
}
// Function invocation
const car = Vehicle("Car", 4);
car.type; // => 'Car'
car.wheelsCount; // => 4
car === window; // => true
Существует два способа гарантировать это:
Не использовать
this
в конструкторе, а собирать начиная с пустого объекта и возвращать его.Проверять, что
this
уже является экземпляром нужного класса в самом начале выполнения конструктора.
Проверка на this
(второй способ):
function Vehicle(type, wheelsCount) {
if (!(this instanceof Vehicle)) {
throw Error("Error: Incorrect invocation");
}
this.type = type;
this.wheelsCount = wheelsCount;
return this;
}
// Constructor invocation
const car = new Vehicle("Car", 4);
car.type; // => 'Car'
car.wheelsCount; // => 4
car instanceof Vehicle; // => true
// Function invocation. Generates an error.
const brokenCar = Vehicle("Broken Car", 3);
new.target
property
new.target
propertyСвойство new.target
позволяет определить была ли функция или конструктор вызваны с помощью оператора new
.
Если функция была вызвана при помощи оператора
new
, тоnew.target
возвращает ссылку на конструктор или функцию.При обычном вызове функции
new.target
имеет значениеundefined
.
function Foo() {
if (!new.target) throw "Foo() must be called with new";
console.log("Foo instantiated with new");
}
Foo(); // throws "Foo() must be called with new"
new Foo(); // logs "Foo instantiated with new"
В конструкторе класса, new.target
ссылается на конструктор, который был непосредственно вызван new
. Это верно и для случая, когда new.target
находится в конструкторе родительского класса, а тот в свою очередь вызывается из конструктора дочернего класса.
class A {
constructor() {
console.log(new.target.name);
}
}
class B extends A {
constructor() {
super();
}
}
const a = new A(); // logs "A"
const b = new B(); // logs "B"
Подробнее: MDN: new.target
Last updated
Was this helpful?