Что такое "new.target"?

Спецификация ECMAScript 2015 упоминает ключевое слово (или слова?) New.target ровно 3 раза - 1 раз в 14.2.3:

Обычно Contains не просматривает большинство форм функций. Однако Contains используется для обнаружения использования new.target, this и super в ArrowFunction.

и дважды в 14.2.16:

ArrowFunction не определяет локальные привязки для аргументов, super, this или new.target. Любая ссылка на аргументы, super, this или new.target в ArrowFunction должна преобразовываться в привязку в лексической среде.

MDN упоминает об этом, но очень расплывчато и страница неполна.

Бабель, кажется, не поддерживает это. Я получил синтаксические ошибки при попытке использовать new.target в функции (стрелка или другие).

Что это такое и как его использовать?

2 ответа

Решение

Вы не нашли его в спецификации, потому что в определениях синтаксиса он пишется с пробелами, как new . target, Название выражения NewTargetи вы найдете этот термин несколько раз.

NewTarget является первым из так называемых мета-свойств и может быть найден в §12.3.8.

Его единственная цель - получить текущее значение [[NewTarget]] текущего значения (без стрелки) функциональной среды. Это значение, которое устанавливается при вызове функции (очень похоже на this обязательный), и в соответствии с §8.1.1.3 Записи среды функций:

Если эта запись среды была создана внутренним методом [[Construct]], то [[NewTarget]] является значением [[Construct]] newTarget параметр. В противном случае его значение undefined,

Итак, с одной стороны, наконец, мы можем определить, была ли функция вызвана как конструктор или нет.

Но это не его настоящая цель. Так что же тогда? Это часть способа, которым классы ES6 являются не только синтаксическим сахаром, и как они позволяют нам наследоваться от встроенных объектов. Когда вы звоните class конструктор через new X, this значение еще не инициализировано - объект еще не создан при вводе тела конструктора. Он создается супер-конструктором во время super() вызов (который необходим, когда предполагается создание внутренних слотов). Тем не менее, экземпляр должен наследоваться от .prototype первоначально вызванного конструктора, и вот где newTarget вступает в игру. Он содержит "самый внешний" конструктор, который получил new звонить во время super() вызовы. Вы можете следить за этим в спецификации, но в основном это всегда newTarget не исполняемый в данный момент конструктор, который передается в OrdinaryCreateFromConstructor процедура - например, в шаге 5 из §9.2.2 [[Construct]] для пользовательских функций.

Длинный текст, может быть, пример лучше подходит:

class Parent {
    constructor() {
        // implicit (from the `super` call)
        //    new.target = Child;
        // implicit (because `Parent` doesn't extend anything):
        //    this = Object.create(new.target.prototype);
        console.log(new.target) // Child!
    }
}
class Child extends Parent {
    constructor() {
        // `this` is uninitialised (and would throw if accessed)
        // implicit (from the `new` call):
        //    new.target = Child 
        super(); // this = Reflect.construct(Parent, [], new.target);
        console.log(this);
    }
}
new Child;

Это в первую очередь предназначен для лучшего определения, когда конструктор вызывается без new,

С http://www.2ality.com/2015/02/es6-classes-final.html:

new.target является неявным параметром, который есть у всех функций. Это конструктор вызывает то, что this это вызовы метода.

Так что я могу написать:

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

Есть больше деталей о том, как это работает, и больше контекстов, в которых это полезно, но мы оставим это здесь.

Для некоторых заметок о встречах new.targetсм. https://esdiscuss.org/notes/2015-01-27.

Другие вопросы по тегам