JS object-oriented inheritance

Prototype chain

In JS, the prototype chain is the way to implement inheritance. Since there is no concept of class in JS, it implements the inheritance relationship between constructors.

The so-called inheritance is that the properties and methods in the parent can be accessed in the child object. The following code implements the inheritance relationship:

function Animal(){
    this.eatFood = function (){
        console.log('Dinner, dinner')
    }
}
var monkey = new Animal();

function Person(name){
    this.name = name;
}
Person.prototype = monkey;
var people = new Person('Xiao Ming');

function Student(){
    this.goSchool = function (){
        console.log('I went to school')
    }
}
Student.prototype = people;

var stu = new Student();

stu.eatFood();
console.log(stu.name);
stu.goSchool();

result:

Dinner, dinner
 Xiao Ming
 I went to school

Only inherited from the prototype

In the above methods, we need to create objects to implement inheritance. In order to improve efficiency, we can directly add properties and methods to the prototype.
The implementation code is as follows:

function Animal(){}
// Add the eatFood method to the prototype of Animal
Animal.prototype.eatFood = function () {
    console.log('Dinner, dinner')
};

function Person(){}
//Add name to the prototype of Person and inherit members from Animal
Person.prototype = Animal.prototype;
Person.prototype.name = 'Xiao Ming';

function Student(){
    this.goSchool = function (){
        console.log('I went to school')
    }
}
//Inherit the prototype of Person for the prototype of Student
Student.prototype = Person.prototype;

var stu = new Student();
stu.goSchool();
console.log(stu.name);
stu.eatFood()

The third line of code must be added to the prototype, otherwise the prototype is an empty object, and the prototype inherited by the following function is also an empty object.

The order of lines 9 and 10 cannot be reversed, otherwise the prototype of Animal will be assigned to the prototype of Person. The name attribute of the prototype on line 9 will be overwritten

result:

I went to school
 Xiao Ming
 Dinner, dinner

The problem of prototype chain inheritance

As mentioned before, JS does not inherit. Our previous tests only realized something similar to inheritance through the prototype chain, to be exact, sharing.
The inheritance of prototype chain implementation is problematic. The following code:

function Animal() {}
Animal.prototype.a = 'this is Animal';

function Person() {}
Person.prototype = Animal.prototype;
Person.prototype.p = 'this is Person';

function Student() {}
Student.prototype = Person.prototype;
Student.prototype.s = 'this is Student';

var stu = new Student();
var ani = new Animal();
var per = new Person();

// In "parent", you can also access the properties in the child object, so it is shared
console.log(stu.a);
console.log(ani.s);
console.log(per.s);

result:

this is Animal
this is Student
this is Student
  • The inheritance implemented by the prototype chain actually shares the properties and methods of the constructor.
  • When you create a child object, you cannot pass parameters to the parent.

Prototype inheritance

Prototype inheritance is to define a function, pass in a formal parameter of Object type in the function, and create a temporary constructor in the function,
The prototype of the temporary constructor points to the formal parameter of the passed in Object type, and then returns the Object constructed by the temporary constructor.
The implementation code is as follows:

function fn1(obj) {
    function innerFun() {}
    innerFun.prototype = obj;
    return new innerFun();
}

var obj = {
    name: 'Xiao Ming'
};

var result = fn1(obj);

console.log(result.name);

result:

Xiao Ming

We can transform it and define our own properties and methods in the external constructor. The implementation code is as follows:

function fn1(obj, args) {
    innerFun.prototype = obj;
    function innerFun() {
        for (var attr in args){
            this[attr] = args[attr]
        }
    }
    return new innerFun();
}

var parentObj = {
    name: 'Xiao Ming'
};

var obj1 = fn1(parentObj,{
    age: 18,
    say: function () {
        console.log('this is say function');
    }
});

console.log(obj1.age);
obj1.say();

//Check whether the say method is the self owned attribute of obj1
console.log(obj1.hasOwnProperty('say'));

The key code is 1-9 lines

result:

18
this is say function
true

Object. The create () method implements inheritance

The create method in Object has the same implementation principle as the method mentioned above, but it is used in different ways.

Syntax structure:

Object.create(obj, {
    attr : {
        value: value,
        writable: true/false,
        ...
    },
    func : {
        value: function () {
            ...
        },
        writable: true/false,
        ...
    },
    ...

Example code:

var obj = {
    name: 'Xiao Ming'
};

var newObj = Object.create(obj, {
    age : {
        value: 18,
        writable: true
    },
    say: {
        value: function () {
            console.log('I'm Xiao Ming')
        },
        writable: false
    }
});

console.log(newObj.age);
newObj.say();

result:

18
 I'm Xiao Ming

The difference between this method and the above method is that this method can only write attributes or methods in the form of attribute descriptors.

Inheritance with constructor (essence)

This method is mainly realized by adding this keyword to call and apply functions. The core of the implementation is the flexibility of this keyword plus JS function.
In fact, the principle is to use the call or apply method to call the parent constructor in the child constructor, flexibly pass parameters through this, and add some parameters.
It can be more similar to the inheritance of other languages.

Look at the short version code:

function Person() {
    this.name = 'Xiao Ming';
}

function Student(){
    Person.apply(this);
    this.age = 16;
}

var stu = new Student();
console.log(stu);

Readers should pay close attention to this here because it is the core of this method.

Code analysis:

  • First, let's look at the Student function. We learned from the previous study that when the function is called, a this will be automatically passed in,
    Line 6 passes the object created by the Student function into the Person method.
  • Next, enter the Person method, which also receives a this, which we call in the Student function
    This is passed here, because this is passed without relying on formal parameters. In other words, this here still represents
    The object created by the Student function (provided that it is called in the Student). Then set the object for Student
    Created a name attribute.

Print results:

Student { name: 'Xiao Ming', age: 16 }

After understanding the simplified version above, we change the parameters in the parent to those defined by formal parameters.
To implement this method, we need to look at the call and apply methods. Here is the code:

function Parent(name) {
    this.name = name;
}
function Son(name, age) {
    Parent.call(this, name);
    this.age = age;
}
var son1 = new Son('Eldest son', 18);
var son2 = new Son('youngest son', 3);

console.log(son1);
console.log(son2);

result:

Son { name: 'Eldest son', age: 18 }
Son { name: 'youngest son', age: 3 }

Inheritance combination

The so-called combinatorial inheritance is to integrate the above inheritance methods and take their advantages. Thus, it is called a better solution. The following code is shown:

function Person(name) {
    this.name = name;
}
Person.prototype.say = function () {
    console.log('I am a person');
};

function Student(name, age) {
    Person.call(this, name);
    this.age = age;
}
Student.prototype = Person.prototype;
Student.prototype.job = 'student';

var stu = new Student('Xiao Ming', 15);

stu.say();
console.log(stu.name);
console.log(stu.age);
console.log(stu.job)

result:

I am a person
 Xiao Ming
15
 student

Encapsulation inheritance method

ps: I will keep updating about the way of inheritance

Tiezi who has learned other languages must know that the keyword extends is used to realize inheritance in inheritance. but, this word is a reserved word in ES5 and in ES6
Can be used to realize inheritance. We forge a myextensions method to realize inheritance. In the future, we need to call the method directly.

This method has a built-in internal constructor. Two objects are required in the formal parameters, a parent object and a child object. We add the properties and methods in the parent object to the internal constructor
On the prototype of the constructor, add the properties and methods in the child object to the object created by the internal constructor, and then return this object.

Implementation code:

function myExtends(parentObj, childObj) {
    function createObj() { }

    createObj.prototype = parentObj;

    var newObj = new createObj();

    for (attr in childObj){
        newObj[attr] = childObj[attr];
    }

    return newObj;
}

Code analysis:

The first is line 2, which defines an empty constructor.

Line 4 points the prototype of the internal constructor to the first parameter. That is, the parent object. In this way, the created object has the properties and methods in the parent.

Line 6 creates an object to be returned.

Lines 8-10 use iterators to add the properties and methods in the child object to the object to be returned.

Tags: Javascript OOP prototype

Posted by richardbotw on Mon, 09 May 2022 09:51:08 +0300