Prototype
TL;DR
- Prototypes are like parents, objects are like children, and just as children inherit genes from their parents, objects inherit properties and methods from their prototypes.
- Use the
__proto__
property or theObject.getPrototypeOf()
method to get an object's prototype. - A constructor function is a type of function used to create objects when called with the
new
keyword. __proto__
is a property of objects that points to their prototype, whileprototype
is a property of functions that is used to define the properties and methods inherited by objects created with that function.
What is prototype
In JavaScript, every object has a prototype, which is a reference to another object that the current object inherits properties and methods from.
The properties and methods defined on the prototype can be accessed and used by the object.
Prototypes are like parents, objects are like children.
Just as children inherit genes from their parents, objects inherit properties and methods from their prototypes.
What is prototype chain
When accessing an object's property or method, JavaScript engine first looks for it in the object itself.
If it's not found there, it searches for it on the object's prototype, so on and so forth, until the end of the prototype chain is reached (which is when the prototype is null
).
This path of searching is called the prototype chain.
How to get the object's prototype
Every object has a hidden property called [[Prototype]]
which points to its prototype.
However, since [[Prototype]]
cannot be directly accessed, it can be accessed through __proto__
or Object.getPrototypeOf()
.
const person = {
isHuman: true,
};
// create a new object and set person object as its prototype
const jordan = Object.create(person);
console.log(jordan.__proto__); // { isHuman: true }
console.log(jordan.__proto__ === Object.getPrototypeOf(jordan)); // true
As __proto__
has been deprecated, we usually use Object.getPrototypeOf()
in practice.
Constructor Function
Actually, a constructor function is just a regular function, but it's used with the new
keyword to create objects.
Before ES6, JavaScript didn't have the class syntax. Instead, objects were created using constructor functions.
Constructor functions do not have a defined return value by default.
function Person(name) {
this.isHuman = true;
this.name = name;
}
const jordan = new Person('jordan');
console.log(jordan); // { name: 'jordan', isHuman: true }
However, if a custom object is returned from the constructor function, it will replace the newly created object.
function Person(name) {
this.isHuman = true;
this.name = name;
return { name: 'John' }; // return a custom object
}
const jordan = new Person('jordan');
console.log(jordan); // { name: 'John' }
prototype
property
Constructor function has the prototype
property that allows objects created by the constructor function to inherit its properties or methods.
function Person(name) {
this.isHuman = true;
this.name = name;
}
Person.prototype.greet = function () {
console.log('I am ' + this.name);
};
const jordan = new Person('jordan');
console.log(jordan); // Person { isHuman: true, name: 'jordan' }
console.log(jordan.__proto__); // { greet: ƒ, constructor: ƒ }
console.log(jordan.greet()); // I am jordan
However, why don't we just define the properties or methods in the constructor function 🤔
The main reason is to save memory usage.
Defining properties and methods directly in the constructor function use more memory when creating many objects, because they are recreated for each object.
function Person(name) {
this.name = name;
// Define method directly in the constructor function
this.greet = function () {
console.log('I am ' + this.name);
};
}
const jordan = new Person('jordan');
console.log(jordan); // Person { name: 'jordan', greet: ƒ }
By defining common properties and methods on the prototype
property, they can be shared among all instances of objects created using that constructor function, leading to better performance and memory usage.
function Person(name) {
this.name = name;
}
Person.prototype.greet = function () {
console.log('I am ' + this.name);
};
const jordan = new Person('jordan');
console.log(jordan); // Person { name: 'jordan' }
console.log(jordan.__proto__); // { greet: ƒ, constructor: ƒ }
__proto__
vs. prototype
__proto__
- A property of every object.
- A way for an object to access its prototype chain.
prototype
- A property of a function.
- A way to add properties and methods to all objects created by that constructor function using the
new
keyword.
function Person(name) {
this.name = name;
}
const jordan = new Person('jordan');
console.log(jordan.__proto__ === Person.prototype); // true
new
keyword
To create an object, we use a constructor function with the new
keyword.
But, how does the new
keyword work under the hood 🤔
According to definition of MDN, new
will do the following things:
- Creates a empty object.
- Sets empty object's
[[Prototype]]
to constructor function'sprototype
- Executes the constructor function and binds empty object as
this
context. - If the constructor function returns an object, the new keyword will return that object. If it doesn't, the new keyword will return the newly created empty object.
function myNew(constructorFn, ...args) {
// 1. Creates a empty object
// 2. Sets empty object's [[Prototype]] to constructor function's prototype
const obj = Object.create(constructorFn.prototype);
// 3. Executes the constructor function and binds empty object as this context
const result = constructorFn.apply(obj, args);
// 4. If the constructor function returns an object
// If it does, new keyword will return that object
// If it doesn't, the new keyword will return the newly created empty object.
return result instanceof Object ? result : obj;
}
function Person(name) {
this.name = name;
}
const jordan = myNew(Person, 'jordan'); // Person { name: 'jordan' }
Reference:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
- https://medium.com/手寫筆記/javascript-new-operator-implementation-8c0d15f2b899
- https://pjchender.blogspot.com/2016/06/javascriptfunction-constructornew.html
- https://www.explainthis.io/zh-hant/interview-guides/javascript/most-common-js-prototype-questions