The new.target property
As part of the ES2015 goodies we get the new.target
property.
In JavaScript, functions are invoked as constructors when called with the new
keyword.
The this
value for a constructor function is the object returned by the function, for a normal function this
would be the global object. if a constructor
function is mistakenly called without the new
keyword, this
becomes the global object, causing unexpected issues.
To protect against this, prior to ES2015 the instanceof
operator was used as shown below
function Foo() {
if (!(this instanceof Foo)) {
throw "Foo must be called with new";
}
}
The instanceof
operator just checks if the prototype of the constructor function can be found on the prototype chain of the object. If that’s the case,
we know the object is an instance of that constructor.
new.target
The new.target
property also allows us determine if a function or constructor has been invoked with the new
keyword. An interesting note, is that new.target
is a meta
property avaliable to all functions and not a target
property on some sort of new
object ( impossible since new
is reserved ) i.e new.target !== new[target]
.
For functions not invoked with the new
keyword, new.target
is undefined
.
function Test() {
console.log(new.target);
}
Test(); // logs undefined
new Test(); // logs "Test" object
For class constructors ( ES2015 classes ), new.target
is the constructor directly invoked by the new
keyword, this also applies to subclasses where the parent class
constructor is delegated from the child class constructor.
class Parent {
constructor() {
console.log(new.target);
}
}
class Child extends Parent {
constructor() {
super();
}
}
new Parent(); // logs "Parent" object
new Child(); // logs "Child" object
For arrow functions, the new.target
will always refer to the new.target
of its immediate enclosing function.
function Foo() {
console.log("enclosing function ->", new.target);
(() => console.log("inner arrow function ->", new.target))();
}
We can now rewrite the the first sample code which uses instanceof
to look like this instead
function Foo() {
if (!new.target) {
throw "Foo must be called with new";
}
}
References