Inheritance in JS (part 1)

For those of you who have learned Java or c# or something like that, you should be very confused about js inheritance — don’t ask me how I know,js inheritance is mainly based on prototype (prototype). For those of you who are interested in js prototype, you can check out the prototype object in js I wrote before

I believe that many students also like me, at the beginning of the contact with JS object-oriented programming, are holding a mentality of rejection — why js so troublesome? In fact, after understanding the prototype chain, then look at JS inheritance, you will find that JS inheritance is actually simpler than other OOP languages, more flexible, let’s look at an inheritance based on the prototype chain

Function Person() {} // Class Student(){} // Class Student(){} // Class Student() = new Person();Copy the code

We just set the prototype of the subclass to an instance of the parent class, and we’re done inheriting, okay? Super simple? Is it clearer than Java,C#? In fact, this is the prototype chain inheritance in JS

Student inherits a shell of Person, which makes no sense. The purpose of using inheritance is to obtain the contents of the parent class, so let’s add a little bit of simple content to the parent class (the new place marks ‘// new code ‘):

/ / parent function Person (name, age) {enclosing name = name | | 'unknow' new code this. / / age = age | | 0} / / the new code / / subclass function Student(name){this.name = name this.score = 80 // this.score = 80 // this.score = 80 //Copy the code

use

Var stu = new Student(' Lucy ') console.log(stu.name) // Lucy -- console.log(stu.age) // 0 -- console.log(stu.age) // Lucy -- new Student(' Lucy ') console.log(stu.age Console. log(stu.score) // 80 -- Subclass's own attributesCopy the code

In order to reduce the complexity, we only show the inheritance of common properties, not methods. In fact, method inheritance is also very simple. Let’s modify the code a little bit.

/ / parent function Person (name, age) {enclosing name = name | | 'unknow enclosing the age = age | | 0} / / new was a way for the parent class Person. Prototype. Say = Function () {console.log('I am a person')} // Subclass function Student(name){this.name = name this.score = 80} // Subclass function Student(name){this.name = name this.score = 80} Student.prototype = new Person() // Add a new method to the subclass (after inheritance, otherwise it will be overridden) () {// Add code console.log('I am studing')}Copy the code

use

Var stu = new Student(' Lucy ') console.log(stu.name) // Lucy -- console.log(stu.age) // 0 -- console.log(stu.age) // Lucy -- new Student(' Lucy ') console.log(stu.age Console.log (stu.score) // 80 -- Subclass attribute stu.say() // I am a person -- inherited method stu.study() from the parent class // I am studing -- subclass methodCopy the code

So, it looks like we’ve got a complete inheritance, and this is prototype chain inheritance, okay? Doesn’t that make sense? However, one drawback of stereotype chain inheritance is that attributes share reference types if they are reference types, as shown in the following code

Function Person() {this.hobbies = ['music','reading']} // Subclass Student(){// subclass Student(){// subclass Student. Prototype = new Person()Copy the code

use

var stu1 = new Student()
var stu2 = new Student()

stu1.hobbies.push('basketball')

console.log(stu1.hobbies)   // music,reading,basketball
console.log(stu2.hobbies)   // music,reading,basketball
Copy the code

We can see that when we change the attributes of the reference type of STU1, the corresponding attributes of STU2 also change. This is the drawback of stereotype chain inheritance — reference attributes are shared by all instances. So how do we solve this problem? Let’s take a look at the simplest example of using constructor inheritance:

Function Person() {this.hobbies = ['music','reading']} // Subclass function Student(){person.call (this);Copy the code

use

var stu1 = new Student()
var stu2 = new Student()

stu1.hobbies.push('basketball')
console.log(stu1.hobbies)   // music,reading,basketball
console.log(stu2.hobbies)   // music,reading
Copy the code

Thus, we have solved the problem of reference types being shared by all instances

The prototype constructor is implemented in the subclass. This is equivalent to copying the parent code into the subclass. Another benefit of this method is that you can pass arguments to the parent class

Function Student(name){person.call (this,name) // Class Person(name) {person.call (this,name) // class Person(name) {person.call (this,name) // }Copy the code

use

var stu1 = new Student('lucy')
var stu2 = new Student('lili')
console.log(stu1.name)   // lucy
console.log(stu2.name)   // lili
Copy the code

It already looks like Java,C#, right?

However, constructors solve the problem of reference types being shared by all instances, but by solving this problem, a paradoxical problem arises: functions are reference types and cannot be shared. That is, the functions in each instance are the same but not the same function, which is equivalent to copying the function code every time we instantiate a subclass

Function Student(name){Person. Call (this,name)} function Student(name){Person. Call (this,name)}Copy the code

use

var stu1 = new Student('lucy')
var stu2 = new Student('lili')
console.log(stu1.say === stu2.say)   // false
Copy the code

The above code shows that functions of the parent class are not shared under instances of subclasses

conclusion

Inheritance way Inherited core code The advantages and disadvantages
Prototype chain inheritance Student.prototype = new Person() Instance reference type shared
Constructor inheritance Execute in subclass (Student)Person.call(this) The reference type of the instance is not shared

As we can see from the above table, the advantages and disadvantages of the two inheritance methods of stereotype chain inheritance and constructor inheritance are just contradictory. So is there a way to have it both ways? If not, I will not say it,^_^, next please allow me to introduce combinative inheritance

Combinatorial inheritance, is to take the advantages of the above two kinds of inheritance, common attributes using constructor inheritance, function using prototype chain inheritance, this code is a bit more complicated, but believe that with the above foundation, it looks very easy

// function Person() {this.hobbies = ['music','reading']} // Function Person() {this.hobbies = ['music','reading']} // function Person() {this.hobbies = ['music','reading'] Function Student(){person. Call (this)} // Class Student(){person. Call (this)} // Class Student(){person Prototype chain inheritance (Inheritance method)Copy the code

use

Var stu1 = new Student() var stu2 = new Student() stu1.hobbies. Push ('basketball') console.log(stu1.hobbies) // music,reading,basketball console.log(stu2.hobbies) // music,reading console.log(stu1.say == stu2.say) // trueCopy the code

In this way, we can not only achieve the independence of attributes, but also achieve the sharing of functions, isn’t it perfect?

Composite inheritance is said to be the most common method of inheritance in JavaScript.

At this point, we put the JS inside the common inheritance to understand the end, in fact, it is not so difficult! However, let’s summarize three types of inheritance

  1. Stereotype chain inheritance, which shares reference properties
  2. Constructor inheritance, which keeps all attributes to itself, including reference attributes (emphasis on functions)
  3. Combinatorial inheritance, using the prototype chain to inherit the shared attributes, using the constructor to inherit the exclusive attributes, to achieve a relatively perfect inheritance

Why does it say relatively perfect? So far, we’ve only covered three basic types of inheritance. In fact, there are many other JavaScript inheritance methods, so I’m going to break them down so you don’t get tired. If you don’t have the patience to continue, this article will be useful for understanding JavaScript inheritance. But the suggestion reads twice more, deepens impression, I learn JS to inherit of time, that rhinoceros book all was turned over rotten by me, write this text of time, I return turn over one side to write of (hiss!)

If you think it is useful, please add a star to github for this article. Thank you very much. In addition, there are some other tutorials and components about the front-end on Github, interested children can have a look, your support is my biggest motivation.