In JavaScript, new.target is a metaproperty introduced in ES6 that allows you to detect whether a function or constructor was called using the new operator. It serves as a diagnostic tool for ensuring that code intended to be a constructor is actually being used as one, and it plays a critical role in complex class inheritance patterns.
1. Concept and Syntax
Metaproperties are not standard objects; they provide information about the context of the code. new.target is available in all functions, but its value changes depending on how the function was invoked:
- In a constructor call (new): It returns a reference to the constructor or class that was invoked.
- In a regular function call: It returns undefined.
JavaScript
function User(name) {
if (!new.target) {
throw new Error("User() must be called with 'new'");
}
this.name = name;
}
const bob = new User("Bob"); // Works fine, new.target is User
const sue = User("Sue"); // Throws Error, new.target is undefined
2. new.target in Inheritance
This is where the metaproperty becomes truly powerful. In a class hierarchy, new.target always points to the constructor that was directly invoked by the new operator, even if that code is currently executing inside a parent class’s constructor.
JavaScript
class Parent {
constructor() {
console.log("Constructing inside Parent...");
console.log("new.target is:", new.target.name);
}
}
class Child extends Parent {
constructor() {
super(); // Calls Parent constructor
}
}
new Parent(); // new.target is Parent
new Child(); // new.target is Child
3. Creating Abstract Classes
JavaScript does not have a native abstract keyword like Java or C#. However, new.target allows you to simulate abstract classes by preventing the base class from being instantiated directly while still allowing subclasses to inherit from it.
JavaScript
class Shape {
constructor() {
if (new.target === Shape) {
throw new TypeError("Cannot construct Shape instances directly (Abstract Class)");
}
}
}
class Circle extends Shape {}
const c = new Circle(); // Works fine
const s = new Shape(); // Throws: "Cannot construct Shape instances directly"
4. The Arrow Function Limitation
Arrow functions cannot be used as constructors and do not have their own this or new.target. If you use new.target inside an arrow function, it will look for the value in the surrounding (lexical) scope.
JavaScript
function Outer() {
const inner = () => {
console.log(new.target);
};
inner();
}
new Outer(); // Logs the 'Outer' function
Outer(); // Logs 'undefined'
5. Interaction with Reflect.construct()
The Reflect.construct() method allows you to pass a third argument which manually sets what new.target will be inside the constructor. This is an advanced feature used primarily in proxy creation and low-level framework design.
JavaScript
function MyBase() {
console.log(new.target);
}
function VirtualTarget() {}
// Calls MyBase, but makes new.target look like VirtualTarget
Reflect.construct(MyBase, [], VirtualTarget);
