banner
lzyoo

lzyoo

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

QTNND's Brain-Teasing Prototype Chain

😍Introduction to Prototype Chain#

Prototype Object#

A simple beginning

In JS, 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
  • Properties and methods defined on the prototype object can be shared and inherited by all associated instance objects
  • prototype is unique to functions
  • The __proto__ property is unique to objects
  1. When JS creates a function, it generates a prototype property that points to an object, which is the prototype object of that function.

This object contains a constructor property that points to the function.

  1. When declaring an instance object of that function, the object implements a __proto__ property that points to the prototype object (ha) of that instance object, so we can compare the function's prototype and the instance object's __proto__, and the result is of course 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 called directly through ha.constructor
ha.__proto__.constructor === ha.constructor

Prototype Chain#

The prototype chain is simple; just look at the following code.

ha.__proto__.__proto__.__proto__ // null
// Here’s an explanation of why it is null
ha.__proto__ points to the prototype object of Ha
ha.__proto__.__proto__ points to the prototype object of Object, which is the prototype of Ha
ha.__proto__.__proto__.__proto__, 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)
}

// First declare an instance of Haha, call the instance's name property, the printed value is the value of the name property in Ha, because inheritance is used, so if the current instance constructor does not have the property, it will look up the name property of Ha's constructor. If it exists, it will print; if not, it will continue to find the name property of Object's constructor, which still does not exist, resulting in null.
let haha = new Haha()
haha.name // 哈喇

// First declare an instance of Haha and pass parameters, call the instance's name property, the printed value is Wang Laowu.
let haha = new Haha('王老五')
haha.name // 王老五

Relationship Between Constructor, Instance, and Prototype#

The constructor is a function used to create 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's prototype's constructor points to the constructor itself

Inheritance#

Constructor Inheritance#

Use call() to point Parent's this to Child's instance to achieve inheritance.
Advantages

  1. Parameters can be passed to the parent class constructor when creating instances.
  2. Each subclass instance has its own copy of the parent class instance; modifying the parent class instance properties will not affect other subclasses inheriting the same parent class.

Disadvantages

  1. Only inherits properties and methods from the parent class constructor, cannot inherit content from the prototype object.
  2. Cannot reuse.
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, subclasses can use parent class properties and methods.
  2. Subclasses can directly access properties and methods on the parent class prototype object.

Disadvantages

  1. Cannot pass parameters to the parent class constructor.
  2. Parent class reference properties will be shared among all subclasses; if one subclass modifies the reference property, other subclasses will also be affected because they operate on the same memory address.
  3. Parent class private variables will be exposed in subclasses.
function Parent(){
    this.name='father'
    this.hobby = ['唱', '跳']
}
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 // ['唱', '跳', 'rap']
c2.hobby // ['唱', '跳', 'rap']

Combination Inheritance#

Constructor + Prototype Chain

Advantages

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

Disadvantages

  1. Calls the parent class instance 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#

Prototypal inheritance + enhancing objects

Advantages

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

Disadvantages

  1. Calls the parent class instance 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#

Enhancing the functionality of the parent class instance in the subclass constructor

Advantages

  1. Avoids the problem of reference type properties being shared by all instances (prototype chain inheritance).

Disadvantages

  1. Cannot achieve function reuse; each subclass internally instantiates the parent class.
  2. Can access private variables of the parent class, which is essentially the subclass containing the parent class instance.
function Parent() {
    this.name = 'father'
    this.hobby = ['唱', '跳']
}

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#

Enhancing the functionality of the parent class instance in the subclass constructor

Advantages

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

Disadvantages

  1. Cannot achieve function reuse; each subclass internally instantiates the parent class.
  2. Can access private variables of the parent class, which is essentially the subclass containing 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 = ['唱', '跳']
}
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.