> For the complete documentation index, see [llms.txt](https://strctr.gitbook.io/programming/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://strctr.gitbook.io/programming/01-languages/javascript/01-language/c-functions/c2-constructors/05-enforce-new.md).

# 05. Enforce new

Существует серьёзная опасность, связанная с конструктором функций: если при вызове конструктора функций отсутствует ключевое слово `new`, то `this` связывается не с создаваемым объектом, а с глобальным объектом.

```javascript
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
```

Существует два способа гарантировать это:

1. Не использовать `this` в конструкторе, а собирать начиная с пустого объекта и возвращать его.
2. Проверять, что `this` уже является экземпляром нужного класса в самом начале выполнения конструктора.

Проверка на `this` (второй способ):

```javascript
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` позволяет определить была ли функция или конструктор вызваны с помощью оператора `new`.

* Если функция была вызвана при помощи оператора `new`, то `new.target` возвращает ссылку на конструктор или функцию.
* При обычном вызове функции `new.target` имеет значение `undefined`.

```javascript
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` находится в конструкторе родительского класса, а тот в свою очередь вызывается из конструктора дочернего класса.

```javascript
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](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/new.target)
