Before class (Classes), a regular function served as a constructor. new Rectangle(10, 20) creates an object whose prototype is Rectangle.prototype, runs the function with this bound to it and returns it. Properties set on this belong to each instance, methods on prototype are shared, and properties on the function itself act as static members. new.target is undefined when a caller forgets new.
function Rectangle(width, height) {
if (!new.target) throw new TypeError("use new"); // guard against a plain call
this.width = width; // own properties per instance
this.height = height;
}
Rectangle.prototype.area = function () { return this.width * this.height; }; // shared
Rectangle.square = (side) => new Rectangle(side, side); // "static"
const r = new Rectangle(10, 20), s = Rectangle.square(5);
console.log(r.area(), s.area(), r.area === s.area, Object.hasOwn(r, "area"));
try { Rectangle(1, 2); } catch (e) { console.log(e.message); }200 25 true false use new
Put methods on the prototype (prototype, this and new), not inside the constructor, where every instance would get its own copy. A class builds the same structure.