What does the new keyword actually do?
Calling a constructor with new does four things. It creates a brand new empty object. It links that object's prototype to the constructor's prototype property. It runs the constructor with this pointing at the new object. And it returns the new object, unless the constructor explicitly returns something else.
function Point(x, y) {
this.x = x;
this.y = y;
}
const p = new Point(1, 2);
console.log(p.x, p.y); // 1 2
console.log(p instanceof Point); // trueTwo of those steps are easy to forget. The prototype link is set before the constructor body runs, which is why the constructor can call methods that live on the prototype. And the new object is empty when the constructor starts, so anything the constructor does not put on it is simply absent, which is why the this binding matters so much inside a constructor.
The new keyword never comes back empty-handed, even if the constructor does not return anything. It returns the object it created. That is different from calling the same function without new, where the return value is whatever the function returns, and where this is the global object in sloppy mode or nothing at all in strict mode.
There is also a subtlety with primitives. A constructor that returns a primitive is ignored, and you get the new object back. A constructor that returns an object replaces the new object entirely, so you can write a constructor that returns a completely different instance. That behaviour is what makes the pattern of returning a factory result from a constructor possible, and it is also a common source of confusion.