js inheritance, I'm a porter

Posted by atl_andy on Fri, 28 Jan 2022 08:54:40 +0100

It's mainly the boss's js inheritance

This is a transporter Prototype, constructor, instance

The first one he said was prototype chain inheritance:

First, we talk about the prototype, constructor and instance, as well as the relationship between them

1. Prototype: a simple object, which is used to realize the attribute inheritance of the object. It can be simply understood as the father of the object. Each JavaScript object contains one_ proto_ Attribute, pointing to his father (the prototype of the object), available in [obj]_ proto_ Visit

2. Constructor: you can create a new function of an object through new

3. Instance: the object created through the new + constructor is an instance.

Instance pass_ proto_ Point to the prototype, and point to the build function through the constructor.

Take Object as an example:

// Constructor
Object();

// example
const instace = new Object();

// Prototypes can be through [examples]_ proto_  Or [constructor] prototype
const prototype = Object.prototype;

Add a prototype chain:

Prototype chain: to find the attribute of an object, first find out whether the object itself has the attribute. If not, it will follow_ proto_ The property (i.e. prototype) is searched upward until the searched object is null and ends the search.

 

1, Prototype chain inheritance:

// Construct a function to implement general properties and methods, and the new instance method inherits the properties and methods of the constructor
function SuperFun (name,age) {
    // Public properties
    this.name = name
    this.age = age
    this.has = ['head','hand','foot']
    this.say = function () {
        console.log(123465)
    }
}
// Public methods, built on prototypes
SuperFun.prototype.getSuperValue = function () {
    console.log(this.has,'Well, I just have');
    console.log(this.age+'year'+this.name+'Just play');
}

// Prototype chain inheritance is to inherit the parent class through the prototype attribute of prototype
function SubFun (name,age) {
    // Public properties
    this.name = name
    this.age = age
}
// Assign the parent instance object to the child prototype
SubFun.prototype = new SuperFun();    // Prototype chain inheritance
// Instance object 1
let zhangsan = new SubFun('zhangsan',18);
zhangsan.getSuperValue();    // Method to access parent
zhangsan.has.push('Small thin leg');    
console.log(zhangsan.has);     // ["head", "hands", "feet", "small thin legs"]
// Instance object 2
let fwkt = new SubFun('Outlaw maniac',18);
fwkt.getSuperValue();    // Method to access parent
fwkt.has.push('long legs'); 
console.log(fwkt.has);    // ["head", "hands", "feet", "small thin legs", "big long legs"]

Disadvantages: the operation of multiple instances on reference types will be tampered with.

Problems encountered:

1. When writing a public method, I was wondering why I couldn't write the method in the build function. I tried

// There are such
function SuperFun (name,age) {
    // Public properties
    this.name = name
    this.age = age
    this.has = ['head','hand','foot']
    function say () {
        console.log(123465)
    }
}
// Error, uncaught typeerror: Zhangsan say is not a function at <anonymous>:1:10

// There are such
function SuperFun (name,age) {
    // Public properties
    this.name = name
    this.age = age
    this.has = ['head','hand','foot']
    return function say () {
        console.log(123465)
    }
}
// new SuperFun is the function returned

// Finally, I found it. I feel it's a small problem. However, there is always a but. Ah, I won't
function SuperFun (name,age) {
    // Public properties
    this.name = name
    this.age = age
    this.has = ['head','hand','foot']
    this.say = function () {
        console.log(123465)
    }
}
// So you can access say

Public methods can also be written in building functions. Why are they written on prototypes?

The difference between methods written in build functions and on prototypes

Written in the build function, each new instance will open up a say space. If written on the prototype, you only need to let the instance press it_ proto_ (prototype) just find it and save memory.

2,SubFun.prototype = new SuperFun(); / / the prototype chain inherits and gives the instance of the parent new to the prototype of the child, which is the prototype chain. fwkt = new SubFun(), then the prototype of fwkt is its own father. There's nothing wrong with it

 

2, Constructor inheritance

Borrowing the construction instance of the parent class to strengthen the subclass instance is to copy the properties and methods in the constructor of the parent class

function SuperFun (name,age) {
    // Public properties
    this.name = name
    this.age = age
    this.has = ['head','hand','foot']
    this.say = function () {
        console.log(123465)
    }
}
// Public methods, built on prototypes
SuperFun.prototype.getSuperValue = function () {
    console.log(this.has,'Well, I just have');
    console.log(this.age+'year'+this.name+'Just play');
}

function SubFun (name,age) {
    // By copying the parent class
    SuperFun.call(this,name,age);
    // All subclasses have copies of parent instance functions
    // How does the call copy work?
}

// Instance object 1
let zhangsan = new SubFun('Zhang San',18);
zhangsan.getSuperValue();    // VM7072:25 Uncaught TypeError: zhangsan.getSuperValue is not a function at <anonymous>:25:10
zhangsan.has.push('long legs');    
console.log(zhangsan.has);    // ["head", "hands", "feet", "big legs"]

// Instance object 2
let fwkt = new SubFun('Outlaw maniac',18);
fwkt.has.push('Black long straight');    
console.log(fwkt.has);    // ["head", "hand", "foot", "black long straight"]

Disadvantages: you can only inherit the instance properties and methods of the parent class, but cannot inherit the properties and methods on the prototype. Reuse cannot be realized. All subclasses have copies of parent instance functions, which affects performance

Problems encountered:

1. / / by copying the parent class superfun call(this,name,age); / / all subclasses have copies of parent class instance functions
How does the call copy work?

Implementation of call

// The just refreshed is gone, so I'll do it again and don't panic at all
// Another chestnut
let superObj = {
    age: 18,
}
function sub() {
    console.log(this.age);
}
sub.call(superObj);    // 18

// Transform it again
let superObj1 = {
    age: 18,
    sub: function () {
        console.log(this.age);
    }
}
superObj1.sub();    // 18
// I see

// Then officially start call function 2.0
Function.prototype.call2 = function (context) {
    // this here refers to the instance itself, that is, superObj2
    context.fn = this; 
    context.fn();    // Why do I have to assign a value and then execute it? Why can't this(), I can't try it
    delete context.fn;
}

// Test 1.0
let superObj2 = {
    age: 18,
}
let superObj3 = {
    sub: function () {
        console.log(this.age);
    }
}

superObj3.sub.call2(superObj2);  18    // I didn't respond when I declared superObj3. I made a mistake and didn't want to change it
// Test 2.0
let superObj2 = {
    age: 18,
}
function sub () {
    console.log(this.age);
}
sub.call2(superObj2);    // 18

/*
 The first step is to mount a new call2 method on the prototype Function;
 The second step is to take out the instance through this and assign it to the passed in parent. At this time, there will be multiple methods called fn on the parent
 Step 3: the parent's fn method doesn't want others to see, so it's burned after reading and deleted
 sub.call2(superObj2) 
     ==>
 superObj2 = {
    age: 18,
    fn: function (name) {
        console.log(this.age)
    }
 } 
 superObj2.fn();
 delete superObj2.fn;
 That's about it
*/

// Start call function 3.0 to solve indefinite parameters
/*
 arguments Object is a local variable that can be used in all (non arrow) functions. This object contains each parameter passed to the function
*/
Function.prototype.call2 = function (context) {
    context.fn = this;
    let args = [...arguments].slice(1);
    context.fn(...args);
    delete context.fn;
}

// Start call function 4.0, when the context is null
Function.prototype.call2 = function (context1) {
    const context = context1 || window;    // If null, point to window
    context.fn = this;
    let args = [...arguments].slice(1);
    let result = context.fn(...args);
    delete context.fn;
    return result;    // When you return, call2 becomes context fn
}

// test
obj1 = {
    value: 1,
}

function aa1(name,age) { 
    console.log( { value: this.value,name,age }) 
}

aa1.call2(obj1,'dengsn',12);    // {value: 1, name: "dengsn", age: 12}

/*
    // Handle the object to be pointed to from the context, or null
    const context = context1 || window;    // If null, point to window

    // Process args
    let args = [...arguments].slice(1);    // All parameters except the first context1 parameter

    superObj2 = {
        age: 18,
        fn: function (...args) {    // Expand parameter transfer
            console.log(this.age)
            ...
        }
     } 
     superObj2.fn(...args);
     delete superObj2.fn;
     return superObj2.fn(...args);    // I don't know why I want to return 

 return After call2 () = = superobj2 fn(...args),
That's Aa1 call2(obj1,'des',12) === aa1. superObj2. fn(...args,obj1,'des',12);
I don't understand. I don't understand
*/
// It's over. It's one step closer to the vegetable chicken



 

3, Combinatorial inheritance

function SuperFun (name,age) {
    // Public properties
    this.name = name
    this.age = age
    this.has = ['head','hand','foot']
    this.say = function () {
        console.log(123465)
    }
}
// Public methods, built on prototypes
SuperFun.prototype.getSuperValue = function () {
    console.log(this.has,'Well, I just have');
    console.log(this.age+'year'+this.name+'Just play');
}
// Prototype chain inheritance is to inherit the parent class through the prototype attribute of prototype
function SubFun (name,age,address) {
    // By copying parent properties
    SuperFun.call(this,name,age);
    this.address = address;
}

SubFun.prototype = new SuperFun()  //Prototype chain inheritance
// console.log(SubFun.prototype.constructor); // Point to SuperFun
// Override SubFun The constructor attribute of prototype points to its own constructor SubFun
SubFun.prototype.constructor = SubFun;
// Instance object 1
let zhangsan = new SubFun('zhangsan',18,'Ningbo, Zhejiang');
zhangsan.getSuperValue();    
zhangsan.has.push('Small thin leg');    
console.log(zhangsan.has);     
// Instance object 2
let fwkt = new SubFun('Outlaw maniac',18,'Ningbo, Zhejiang');
fwkt.getSuperValue();    
fwkt.has.push('long legs'); 
console.log(fwkt.has);    

Disadvantages: when using subclasses to create instance objects, there will be two identical properties / methods on the prototype

4, Parasitic combinatorial inheritance

Parasitic combinatorial inheritance: it realizes inheritance by combining constructor passing parameters and parasitic pattern

// parasitic 
function inheritPrototype (subType,superType) {
    // Create an object to cache the parent class prototype
    let _prototype = Object.create(superType.prototype);
    // Assign the prototype of the parent class to the prototype of the child class
    subType.prototype = _prototype;
    // Enhanced object
    _prototype.constructor = subType;    // Prevent the default constructor property from being lost by rewriting the prototype
}

// The parent class initializes instance properties and prototype properties
function SuperFun (name,age) {
    // Public attribute
    this.name = name
    this.age = age
    this.has = ['head','hand','foot']
}
// Public methods are written on prototypes
SuperFun.prototype.getSuperValue = function () {
    console.log(this.has,'Well, I just have');
    console.log(this.age+'year'+this.name+'Just play');
}
// Use constructor to pass enhanced subclass instance attribute (support parameter passing and avoid tampering)
function SubFun (name,age,sex) {
    // Copy parent class
    SuperFun.call(this,name,age);
    this.sex = sex;
}
// Point the parent class prototype to the child class
inheritPrototype(SubFun,SuperFun);
// Add subclass prototype attribute
SubFun.prototype.saySex = function () {
    console.log(this.sex);
}
let instance1 = new SubFun('ss',12,'female')
instance1.has.push('aa')
let instance2 = new SubFun('gg',11,'male')
instance2.has.push('bb')
console.log(instance1);
console.log(instance2);

This is the most mature inheritance method at present. I think it is constructor inheritance, and then point the parent class prototype to the child class prototype.. I'm too sleepy. My brain doesn't turn.

5, ES6 class inherits extensions

The extends keyword is mainly used in class declarations or class expressions to create a class that is a subclass of another class.

Constructor represents a constructor. A class can only have one constructor. Multiple constructors will report SyntaxError errors

If the specified constructor method is not displayed, the default constructor method is added

The subclass inherits the parent class with super

class Rectangle {
    constructor(w,h){
        this.height = h
        this.width = w
    }
    get area(){
        return this.width*this.height
    }
}
const reactangle = new Rectangle(10,20)
console.log(reactangle.area); //200
console.log(reactangle);
// ------------------------Inherit--------------------------------
class Square extends Rectangle {
    constructor(length){
        super(length,length)
       // If there is a constructor in the subclass, you need to call super() before using "this".
        this.name='square'
    }
    get area(){
        return this.width*this.height
    }
}
const square = new Square(10)
console.log(square.area); //100
console.log(square);

The above is the first link I copied. I don't want to write it. I'm sleepy.

The core code of extensions is as follows, which is the same as parasitic composite inheritance

function _inherits(subType, superType) {
  
    // Create an object and create a copy of the parent class prototype
    // Enhance the object to make up for the loss of the default constructor attribute due to rewriting the prototype
    // Specify the object and assign the newly created object to the prototype of the subclass
    subType.prototype = Object.create(superType && superType.prototype, {
        constructor: {
            value: subType,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    
    if (superType) {
        Object.setPrototypeOf 
            ? Object.setPrototypeOf(subType, superType) 
            : subType.__proto__ = superType;
    }
}

/*
     Analyze it
     Object.create There are two parameters, the first is the object, and the second is the and object Defineproperty is the same as editing whether it is readable or writable.
    superType && superType.prototype This means that if there is a superType, use superType Prototype is a & & operation
    constructor Supertype. Is specified Prototype has a property called constructor, and then the descriptor in the object
    The following should be to make the parent class prototype point to the child class prototype
   

*/

What is the difference between function declaration and class declaration?

The function declaration will have variable promotion, and the class declaration does not. If the class is not declared, the access will report an error.

console.log(obj1);    // VM22125:1 Uncaught ReferenceError: obj1 is not defined
let obj1 = {
    age: 18
}

console.log(obj2);    // f obj2() {age:18}
function obj2() {
    age: 18
}

 

Topics: Javascript