Spec-Zone.ru › JavaScript

new.target

Baseline Широко доступно

Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна в браузерах с марта 2016 года.

Мета-свойство new.target позволяет определить, была ли функция или конструктор вызвана с использованием оператора new. В конструкторах и функциях, вызванных с использованием оператора new, new.target возвращает ссылку на конструктор или функцию, для которой new был вызван. При обычных вызовах функций new.target является undefined.

Попробуйте

function Foo() {
  if (!new.target) {
    throw new TypeError("calling Foo constructor without new is invalid");
  }
}

try {
  Foo();
} catch (e) {
  console.log(e);
  // Expected output: TypeError: calling Foo constructor without new is invalid
}

Синтаксис

new.target

Значение

new.target гарантированно является конструируемым значением функции или undefined.

  • В конструкторах классов он ссылается на класс, для которого new был вызван, который может быть подклассом текущего конструктора, поскольку подклассы транзитивно вызывают конструктор суперкласса через super().
  • В обычных функциях, если функция сконструирована напрямую с помощью new, new.target ссылается на саму функцию. Если функция вызывается без new, new.target является undefined. Функции могут использоваться в качестве базового класса для extends, в этом случае new.target может ссылаться на подкласс.
  • Если конструктор (класс или функция) вызывается через Reflect.construct(), то new.target ссылается на значение, переданное в качестве newTarget (по умолчанию target).
  • В стрелочных функциях new.target наследуется из окружающей области видимости. Если стрелочная функция не определена внутри другого класса или функции, которая имеет new.target связывание, то выбрасывается синтаксическая ошибка.
  • В блоках статической инициализации new.target является undefined.

Описание

Синтаксис new.target состоит из ключевого слова new, точки и идентификатора target. Поскольку new является зарезервированным словом, а не идентификатором, это не аксессор свойства, а специальный синтаксис выражения.

Мета-свойство new.target доступно во всех телах функций/классов; использование new.target вне функций или классов является синтаксической ошибкой.

Примеры

new.target в вызовах функций

При обычных вызовах функций (в отличие от вызовов функций-конструкторов) new.target является undefined. Это позволяет определить, была ли функция вызвана с new в качестве конструктора.

function Foo() {
  if (!new.target) {
    throw new Error("Foo() must be called with new");
  }
  console.log("Foo instantiated with new");
}

new Foo(); // Logs "Foo instantiated with new"
Foo(); // Throws "Foo() must be called with new"

new.target в конструкторах

В конструкторах классов new.target ссылается на конструктор, который был напрямую вызван new. Это также верно, если конструктор находится в родительском классе и был делегирован из конструктора дочернего класса. new.target указывает на класс, для которого new был вызван. Например, когда b был инициализирован с помощью new B(), было выведено имя B; аналогично, в случае a было выведено имя класса A.

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"

new.target с использованием Reflect.construct()

До Reflect.construct() или классов, наследование обычно реализовывалось путем передачи значения this, и позволения базовому конструктору изменять его.

function Base() {
  this.name = "Base";
}

function Extended() {
  // Only way to make the Base() constructor work on the existing
  // `this` value instead of a new object that `new` creates.
  Base.call(this);
  this.otherProperty = "Extended";
}

Object.setPrototypeOf(Extended.prototype, Base.prototype);
Object.setPrototypeOf(Extended, Base);

console.log(new Extended()); // Extended { name: 'Base', otherProperty: 'Extended' }

Однако call() и apply() фактически *вызывают* функцию, а не *конструируют* ее, поэтому new.target имеет значение undefined. Это означает, что если Base() проверяет, сконструирован ли он с new, будет выброшена ошибка, или он может работать другим неожиданным образом. Например, вы не можете расширить Map таким образом, потому что конструктор Map() не может быть вызван без new.

Все встроенные конструкторы напрямую конструируют всю цепочку прототипов нового экземпляра, считывая new.target.prototype. Поэтому, чтобы убедиться, что (1) Base сконструирован с new, и (2) new.target ссылается на подкласс, а не на сам Base, нам нужно использовать Reflect.construct().

function BetterMap(entries) {
  // Call the base class constructor, but setting `new.target` to the subclass,
  // so that the instance created has the correct prototype chain.
  return Reflect.construct(Map, [entries], BetterMap);
}

BetterMap.prototype.upsert = function (key, actions) {
  if (this.has(key)) {
    this.set(key, actions.update(this.get(key)));
  } else {
    this.set(key, actions.insert());
  }
};

Object.setPrototypeOf(BetterMap.prototype, Map.prototype);
Object.setPrototypeOf(BetterMap, Map);

const map = new BetterMap([["a", 1]]);
map.upsert("a", {
  update: (value) => value + 1,
  insert: () => 1,
});
console.log(map.get("a")); // 2

Примечание: Фактически, из-за отсутствия Reflect.construct(), невозможно корректно подклассировать встроенные объекты (например, подклассы Error) при трансляции в код до ES6.

Однако, если вы пишете код ES6, предпочтительнее использовать классы и extends вместо этого, так как это более читаемо и менее подвержено ошибкам.

class BetterMap extends Map {
  // The constructor is omitted because it's just the default one

  upsert(key, actions) {
    if (this.has(key)) {
      this.set(key, actions.update(this.get(key)));
    } else {
      this.set(key, actions.insert());
    }
  }
}

const map = new BetterMap([["a", 1]]);
map.upsert("a", {
  update: (value) => value + 1,
  insert: () => 1,
});
console.log(map.get("a")); // 2

Спецификации

Спецификация
Спецификация языка ECMAScript® 2027
# sec-built-in-function-objects

Совместимость с браузерами

Настольные Мобильные Сервер
Chrome Edge Firefox Opera Safari Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet WebView Android WebView on iOS Bun Deno Node.js
new_target
46
13
41
33
11
46
41
33
11
5.0
46
11
1.0.0
1.0
5.0.0

См. также

  • Функции
  • Классы
  • new
  • this

© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API