33

The ECMAScript 2015 specification mention the keyword (or words?) new.target exactly 3 times - 1 time in 14.2.3:

Normally, Contains does not look inside most function forms However, Contains is used to detect new.target, this, and super usage within an ArrowFunction.

and twice in 14.2.16:

An ArrowFunction does not define local bindings for arguments, super, this, or new.target. Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment

MDN mentions it, but is very vague and the page is incomplete.

Babel doesn't seem to support it. I got syntax errors when trying to use new.target in a function (arrow or others).

What is it, and how is it supposed to be used?

Elias Zamaria
  • 80,938
  • 29
  • 103
  • 136
Amit
  • 41,690
  • 8
  • 66
  • 101

2 Answers2

45

You didn't find it in the spec because in the syntax definitions it is written with blanks, as new . target. The name of the expression is NewTarget, and you'll find that term a few times around.

NewTarget is the first of the so-called meta properties and can be found in §12.3.8.

Its sole purpose is to retrieve the current value of the [[NewTarget]] value of the current (non-arrow) function environment. It is a value that is set when a function is called (very much like the this binding), and according to §8.1.1.3 Function Environment Records:

If this Environment Record was created by the [[Construct]] internal method, [[NewTarget]] is the value of the [[Construct]] newTarget parameter. Otherwise, its value is undefined.

So, for one thing, finally enables us to detect whether a function was called as a constructor or not.

But that's not its real purpose. So what is it then? It is part of the way how ES6 classes are not only syntactic sugar, and how they allow us inheriting from builtin objects. When you call a class constructor via new X, the this value is not yet initialised - the object is not yet created when the constructor body is entered. It does get created by the super constructor during the super() call (which is necessary when internal slots are supposed to be created). Still, the instance should inherit from the .prototype of the originally called constructor, and that's where newTarget comes into the play. It does hold the "outermost" constructor that received the new call during super() invocations. You can follow it all the way down in the spec, but basically it always is the newTarget not the currently executed constructor that does get passed into the OrdinaryCreateFromConstructor procedure - for example in step 5 of §9.2.2 [[Construct]] for user-defined functions.

Long text, maybe an example is better suited:

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;
Bergi
  • 513,640
  • 108
  • 821
  • 1,164
  • 2
    So that means its valid syntax to write `console.log(new . target)` (with spaces) inside a function? – Amit Sep 08 '15 at 13:27
  • 5
    @Amit: I presume - it's multiple tokens, which can always be separated via whitespace. It's valid ES to write `console . log(…)` as well :-) Of course no one does it - except for line breaks when method chaining… – Bergi Sep 08 '15 at 13:30
  • but that not quite the same. `console` is an identifier, `new` is a keyword. That would make it quite odd when considering `new Obj()` is valid syntax. – Amit Sep 08 '15 at 13:53
  • "this is uninitialized (and throws)", I'm not sure what you're referring to there. – Asad Saeeduddin Sep 08 '15 at 16:20
  • @Amit: Yes, `new.target` is not a single keyword, it's a grammar element consisting of three tokens (one keyword, a dot, and an identifier). – Bergi Sep 08 '15 at 17:45
  • 3
    @Asad: You cannot access `this` before the `super()` call - when you try referencing it, it throws a `ReferenceError`. – Bergi Sep 08 '15 at 17:46
  • @Bergi Ah yes, makes sense. Didn't realize you were referring to `this`. – Asad Saeeduddin Sep 08 '15 at 19:54
  • @Bergi, thanks for the elaborate answer. But I still can't get this part `this = Object.create(new.target.prototype);` - why does parent gets child prototype? `new.target` is a child as you specified – Max Koretskyi Mar 30 '17 at 17:43
  • 2
    @Maximus Not *a* child, but *the* `Child` *constructor* itself. And we want the new instance to inherit from the `Child.prototype` object – Bergi Mar 30 '17 at 17:45
  • Can you give a reference to the spec where Child (is actually its constructor function if I understand right) is get its [[Prototype]] (from Parent)? – Mergasov Dec 26 '17 at 21:58
  • @Mergasov Do you mean [*constructorParent* in step 6 of §14.5.14](http://www.ecma-international.org/ecma-262/6.0/#sec-runtime-semantics-classdefinitionevaluation), i.e. for `Object.getPrototypeOf(Child) === Parent`? Not sure what it has to do with this question. – Bergi Dec 26 '17 at 22:47
8

It's primarily intended as a better way to detect when a constructor is called without new.

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

new.target is an implicit parameter that all functions have. It is to constructor calls what this is to method calls.

So I can write:

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

There are more details to how this works, and more contexts in which it is useful, but we'll leave it here.

For some meeting notes regarding new.target, see https://esdiscuss.org/notes/2015-01-27.

  • I think it is impossible to call a constructor without `new` (you'll get an exception). Unless by "constructor" you mean a regular function called with "new", and I'm just misunderstanding you. – Asad Saeeduddin Sep 08 '15 at 06:26
  • 6
    @Asad A constructor **is** a regular function called with `new`. –  Sep 08 '15 at 06:30
  • 1
    I see. I was thinking of it in the sense of the new ES6 `constructor`-keyword constructors, which TypeError if you don't invoke them with `new`. – Asad Saeeduddin Sep 08 '15 at 06:34
  • Where is any of this defined in the spec? – Amit Sep 08 '15 at 07:36
  • also, a constructor **is not** a regular function, and can't be called ***without*** `new`. – Amit Sep 08 '15 at 07:41
  • 1
    @Amit I'm talking about constructors in the classic sense of `function Foo()`. –  Sep 08 '15 at 07:45
  • Yeah, I re-read these comments, mine is pretty much what Asad already said, and you did explian yourself. – Amit Sep 08 '15 at 07:48
  • There is some information about this at http://www.ecma-international.org/ecma-262/6.0/#sec-built-in-function-objects, but it does not directly describe `new.target`. –  Sep 08 '15 at 07:50
  • Regarding the example with `MyPromise.reject`, that's not what is explained in the 2ality link, and again, nothing of it in the spec. If anything, I'd expect it to have some meaningful value when constructing a new object instance (`new MyPromise.reject()`), but that's not how the typical (standard..) Promise syntax works. – Amit Sep 08 '15 at 07:52
  • Hm, that `Promise.reject` example seems to be really wrong. That function is not expected to be called as a constructor, so you should not use `new.target` at all. The correct approach is to `return new this(…)` in static methods. – Bergi Sep 08 '15 at 12:49
  • @Bergi Thanks, took that out until I figure it out. –  Sep 08 '15 at 13:02