Every object in JavaScript has a built-in property, which is called its prototype. The prototype is itself an object, so the prototype will have its own prototype, making what's called a prototype chain. The chain ends when we reach a prototype that has null for its own prototype.
When you try to access a property of an object: if the property can't be found in the object itself, the prototype is searched for the property. If the property still can't be found, then the prototype's prototype is searched, and so on until either the property is found, or the end of the chain is reached, in which case undefined is returned.
Example
const myDate = new Date();
let object = myDate;
do {
object = Object.getPrototypeOf(object);
console.log(object);
} while (object);
// Date.prototype
// Object { }
// null
Setting ProtoType of Object
Method 1 (Object Assign)
// case 1
function Person(name, age) {
this.name = name;
this.age = age;
this.log = function () {
console.log(this.name + ', age:' + this.age);
}
}
var nick = new Person('nick', 18);
var peter = new Person('peter', 20);
console.log(nick.log === peter.log) // false
// case 2
function Person(name, age) {
this.name = name;
this.age = age;
}
const PersonPrototype = {
log(){
console.log(this.name + ', age:' + this.age);
}
}
Object.assign(Person.protoType, PersonPrototype);
// or Person.prototype.log = personPrototype.log;
var nick = new Person('nick', 18);
var peter = new Person('peter', 20);
console.log(nick.log === peter.log) // true
// since the method is shared without creating new reference same as case 1
Method 2 (By property)
// case 1
const parent = {
value: 2,
method() {
return this.value + 1;
},
};
console.log(parent.method()); // 3
// When calling parent.method in this case, 'this' refers to parent
// child is an object that inherits from parent
const child = {
__proto__: parent,
};
console.log(child.method()); // 3
// When child.method is called, 'this' refers to child.
// So when child inherits the method of parent,
// The property 'value' is sought on child. However, since child
// doesn't have an own property called 'value', the property is
// found on the [[Prototype]], which is parent.value.
child.value = 4; // assign the value 4 to the property 'value' on child.
// This shadows the 'value' property on parent.
// The child object now looks like:
// { value: 4, __proto__: { value: 2, method: [Function] } }
console.log(child.method()); // 5
// Since child now has the 'value' property, 'this.value' means
// child.value instead
// case 2
const obj = {};
// DON'T USE THIS: for example only.
obj.__proto__ = { barProp: "bar val" };
obj.__proto__.__proto__ = { fooProp: "foo val" };
console.log(obj.fooProp);
console.log(obj.barProp);
// case 1
function Base() {}
function Derived() {}
// Set the `[[Prototype]]` of `Derived.prototype`
// to `Base.prototype`
Object.setPrototypeOf(Derived.prototype, Base.prototype);
const obj = new Derived();
// equal
class Base {}
class Derived extends Base {}
const obj = new Derived();
// obj ---> Derived.prototype ---> Base.prototype ---> Object.prototype ---> null
// case 2
// A constructor function
function Box(value) {
this.value = value;
}
// Properties all boxes created from the Box() constructor
// will have
Box.prototype.getValue = function () {
return this.value;
};
// equal
class Box {
constructor(value) {
this.value = value;
}
// Methods are created on Box.prototype
getValue() {
return this.value;
}
}