banner
lzyoo

lzyoo

本人职业:前端开发工程师 工作年限:三年 技术栈:React、Vue、Nest、Python 一直在努力,一直在放弃,好想有一个引路人带领。

QTNND's Mind-boggling Prototype Chain

😍Introduction to the Prototype Chain#

Prototype Object#

Let's start with a simple explanation.

In JavaScript, everything is based on objects

  • The prototype of a function points to the prototype object.
  • The constructor of the prototype object points to the function.
  • The properties and methods defined on the prototype object can be shared and inherited by all associated instance objects.
  • prototype is unique to functions.
  • __proto__ property is unique to objects.
  1. When a function is created in JavaScript, it generates a prototype property that points to an object. This object is the prototype object of that function.

  2. When declaring an instance object of that function, it implements a __proto__ property that points to the prototype object ({constructor:f}) of that instance object (ha). Therefore, we can compare the prototype of the function with the __proto__ of the instance object, and the result is true.

// Create a function named Ha
function Ha(){
    this.name='哈喇'
}
// Call Ha's prototype
Ha.prototype //{constructor:f}

// Declare an instance object
let ha = new Ha()
// Prototype object comparison
ha.__proto__ === Ha.prototype // true
// The constructor can be directly accessed through ha.constructor
ha.__proto__.constructor === ha.constructor

Prototype Chain#

The prototype chain is very simple. You will understand it by looking at the following code.

ha.__proto__.__proto__.__proto__ // null
// Let me explain why it is null here
ha.__proto__ points to the prototype object of Ha
ha.__proto__.__proto__ points to the prototype object of Object, the prototype object of Object is the top-level object, and since everything is based on objects, does the prototype object above Object still exist? Of course not, so it returns null.
// Constructor Inheritance
function Haha(name){
    this.name=name
    Ha.call(this)
}

// Declare an instance of the Haha class first, call the name property of the instance, and the printed value is the value of the name property in Ha. Because inheritance is used, if the property does not exist in the current instance constructor, it will continue to look up the name property of the Ha constructor in the upper level. If it exists, it will be printed. If it does not exist, it will continue to look up the name property of the Object constructor, and it will be null if it still does not exist.
let haha = new Haha()
haha.name // 哈喇

// Declare an instance of the Haha class and pass parameters, and the printed value is Wang Laowu.
let haha = new Haha('王老五')
haha.name // 王老五

Relationship between Constructor, Instance, and Prototype#

A constructor is a function used to construct instances. Each instance has a prototype, and the prototype points to the prototype of the constructor.

// The prototype of ha is Ha.prototype
// The prototype of Ha.prototype is Object.prototype
function Ha(){} // Constructor
let ha=new Ha() // Instance

Ha.prototype.constructor === Ha //true The constructor of the constructor's prototype points to the constructor itself

Inheritance#

Constructor Inheritance#

Use call() to bind the this of the parent to the instance of the child to achieve inheritance.
Advantages:

  1. Parameters can be passed to the parent constructor when creating an instance.
  2. Each child instance has its own parent instance. Modifying the parent instance property will not affect other child instances that inherit the same parent.

Disadvantages:

  1. Only inherits the properties and methods in the parent constructor, cannot inherit the contents on the prototype object.
  2. Cannot be reused.
function Parent(){
    this.name='father'
}

Parent.prototype.sayHello = function () {
    return this.name
}

function Children(){
    Parent.call(this)
}
const c = new Children()
c.name // father
c.sayHello // c.sayHello is not a function

Prototype Chain Inheritance#

Rewrite the prototype object.
Advantages:

  1. Function reuse, the child class can use the parent class's properties and methods.
  2. The child class can directly access the properties and methods on the parent class's prototype object.

Disadvantages:

  1. Cannot pass parameters to the parent constructor.
  2. Parent reference properties will be shared by all children classes. If one child class modifies the reference property, other child classes will also be affected because they operate on the same memory address.
  3. Parent private variables will be exposed in the child class.
function Parent(){
    this.name='father'
    this.hobby = ['singing', 'dancing']
}
Parent.prototype.sayHello = function(){
    return this.name
}
function Children(){}
Children.prototype = new Parent()
const c = new Children()
const c2 = new Children()
c.name // father
c.sayHello() // father
c.hobby.push('rap')
c.hobby // ['singing', 'dancing', 'rap']
c2.hobby // ['singing', 'dancing', 'rap']

Combination Inheritance#

Constructor + Prototype Chain
Advantages:

  1. Inherit all instance properties and properties on the prototype object of the parent class (excluding private properties).
  2. Avoid the problem of reference type properties being shared by all instances (prototype chain inheritance).

Disadvantages:

  1. Call the parent constructor twice, affecting performance.
function Parent(){
    this.name='father'
}
Parent.prototype.sayHello = function(){
    return this.name
}
function Children(){
    Parent.call(this)
}
Children.prototype = new Parent()
Children.prototype.constructor = Children
const c = new Children()
c.name // father
c.sayHello() // father

Parasitic Inheritance#

Prototype-based inheritance + Enhanced object
Advantages:

  1. Inherit all instance properties and properties on the prototype object of the parent class (excluding private properties).
  2. Avoid the problem of reference type properties being shared by all instances (prototype chain inheritance).

Disadvantages:

  1. Cannot achieve function reuse, each child class internally instantiates the parent class.
  2. Can access parent class private variables, which means that the child class is actually stuffed with the parent class instance.
function Parent() {
    this.name = 'father'
    this.hobby = ['singing', 'dancing']
}

Parent.prototype.sayHello = function () {
    return this.name
}

function Children() {
    let parent = new Parent()
    parent.sayBye = function Bye() {
        return this
    }
    return parent
}
const c = new Children()
console.log(c.sayHello());

Parasitic Combination Inheritance#

Enhanced parent instance functionality in the child class constructor
Advantages:

  1. Avoid the problem of reference type properties being shared by all instances (prototype chain inheritance).
  2. Only called the Parent constructor once.

Disadvantages:

  1. Cannot achieve function reuse, each child class internally instantiates the parent class.
  2. Can access parent class private variables, which means that the child class is actually stuffed with the parent class instance.
function _extends(children, parent) {
    let parent_prototype = Object.create(parent.prototype)
    parent_prototype.constructor = children
    children.prototype = parent_prototype
}
function Parent() {
    this.name = 'father'
    this.hobby = ['singing', 'dancing']
}
Parent.prototype.sayHello = function () {
    return this.name
}
function Children() {
    Parent.call(this)
}

_extends(Children, Parent)
const c = new Children()
console.log(c.sayHello()) // father
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.