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;
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…