The `new` Operator — How a Function Becomes an Object
new is the most puzzling among the four ways this can be invoked. You write new Dog() and get an empty object — what actually happens in between?
Why can you new a function?
function Dog(name: string) {
this.name = name;
}
new Dog("大黄") does the following:
- Creates an empty object, pointing its
__proto__toDog.prototype(see the guide at the end of this post for prototype chain details) - Binds
thisto this empty object, then executes the constructor body this.xxx = ...inside the constructor gets attached to this object- Returns this object (if the constructor doesn’t explicitly return an object)
class is syntactic sugar
// class syntax:
class Dog {
name: string;
constructor(name: string) {
this.name = name;
}
bark() {
console.log(`${this.name}: woof!`);
}
}
// Equivalent prototype syntax:
function Dog(this: any, name: string) {
this.name = name;
}
Dog.prototype.bark = function () {
console.log(`${this.name}: woof!`);
};
Verifying that class is indeed a function:
console.log(typeof Dog); // "function" — class is just function
const d = new Dog("大黄");
console.log(d.bark === Dog.prototype.bark); // true — methods live on the prototype
This also explains why arrow functions as class fields aren’t shared:
class Dog {
bark() {} // → Dog.prototype.bark (shared by all instances)
run = () => {}; // → this.run = () => {} (each instance gets its own copy)
}
run = () => {} is equivalent to defining a regular property — written as this.run = () => {} inside the constructor, attached to the instance, bypassing prototype sharing.
More
new answers “where objects come from”, but not “how methods on the prototype chain are found”:
- What’s the relationship between
__proto__andprototype? - How does the prototype chain look up methods layer by layer?
- How do
instanceofandhasOwnPropertywork under the hood?
Dive deeper here: Prototype Chain — From new an Object to the Essence of Method Sharing