Writing { name: "Camille", balance: 0 } is enough for a single object. As soon as thirty are needed, all built on the same model and carrying the same methods, copying the structure by hand becomes a source of inconsistency.
new is the operator that settles this: it builds an object from a model and gives it access to everything that model knows how to do.
Definition
new comes before the call to a class or a constructor function. It creates an empty object, links it to the model, runs the constructor against that object, then returns it. The result is an instance: it owns its own data and shares the methods of the model.
class Account {
constructor(holder) {
this.holder = holder;
this.balance = 0;
}
credit(amount) {
this.balance += amount;
return this.balance;
}
}
const account = new Account("Camille");
console.log(account.credit(50)); // 50
console.log(account instanceof Account); // trueTwo accounts created from this class would each carry their own balance, yet a single credit function would exist in memory, shared by both.
The four steps, in order
The operator does four things, and knowing which ones explains most of the odd behavior people meet around this.
| Step | What happens |
|---|---|
| 1 | An empty object is created |
| 2 | Its prototype is linked to the model |
| 3 | The constructor runs with this pointing at that object |
| 4 | The object is returned, unless the constructor returns an object itself |
The third step is the one to remember: inside a constructor, this means the instance currently being built.
What happens when it is forgotten
The language protects classes, but not the constructor functions inherited from the older style.
class Account {
constructor(holder) { this.holder = holder; }
}
try {
Account("Camille"); // without new
} catch (error) {
console.log(error.name); // TypeError
}
const arrow = () => {};
try {
new arrow();
} catch (error) {
console.log(error.name); // TypeError
}A class called without the operator raises an error straight away, which is good news. An arrow function likewise refuses to be constructed: it has neither its own this nor a prototype. An ordinary function, on the other hand, runs without complaint and returns undefined, silently.
Never write new in front of Number, String or Boolean. You get a wrapper object rather than a value: typeof new Number(5) is "object", and comparing it to 5 fails under Strict equality (===). These functions are called without the operator, to convert.
Frequently asked questions
Are constructor functions still worth using?
For new code, no: class does the same thing more readably and guards against a call without the operator. Constructor functions remain very present in existing code and in older libraries, so being able to read them keeps its value.
How does it differ from Object.create?
Object.create builds an object by giving it a prototype, without running any constructor at all. The new operator does both, which is what makes it convenient: creation and initialization fit in a single expression. The Object method is mostly useful when no initialization is needed.
Can a constructor return something other than the instance?
Yes, and that is the fourth step in the table: if the constructor explicitly returns an object, the caller receives that object. Returning a simple value, a number or a string, has no effect at all and the instance leaves anyway.