JavaScript Inheritance
Recently, I suddenly found myself a little rusty with JavaScript inheritance, so let’s review it again.
It’s best to review the blog about prototype chains before reading this one: https://sunra.top/posts/7a3d3c75/
Design idea of prototype chain
Ancient times
To understand the design concept of JavaScript, we must start from its birth.
In 1994, Netscape released version 0.9 of the Navigator browser. This is the first relatively mature web browser in history, and it was a sensation. However, this version of the browser can only be used for browsing and does not have the ability to interact with visitors. For example, if there is a column “username” on the webpage that requires filling in, the browser cannot determine whether the visitor really filled in, only let the server side judge. If it is not filled in, the server side returns an error and asks the user to fill it out again, which is a waste of time and server resources.
Therefore, Netscape urgently needed a web scripting language to enable browsers to interact with web pages. EngineerBrendan EichIn charge of developing this new language. He felt that there was no need to design it very complicated. This language only needed to be able to complete some simple operations, such as judging whether the user had filled out a form.
1994 was the heyday of object-oriented programming, C++ was the most popular language at the time, and version 1.0 of the Java language was about to be released the following year, and Sun was building momentum.
Brendan Eich is undoubtedly affected. All data types in Javascript are objects, which is very similar to Java. However, he immediately encountered a dilemma. Should we design an “inheritance” mechanism?
Choice
If it is really a simple scripting language, there is no need for “inheritance” mechanism. However, Javascript is full of objects, and there must be a mechanism to connect all objects. So, Brendan Eich finally designed “inheritance”.
However, he does not intend to introduce the concept of “classes”, because once there are “classes”, Javascript is a complete Object Oriented programming language, which seems a bit too formal and increases the difficulty of getting started for beginners.
He considers that both C++ and Java languages use the new command to generate instances.
C++ is written as:
1 | ClassName *object = new ClassName(param); |
Java is written as:
1 | Foo foo = new Foo(); |
Therefore, he introduced the new command into Javascript to generate an instance object from a prototype object. However, Javascript does not have a “class”, how to represent a prototype object?
At this point, he thought that C++ and Java use the new command, they all call the constructor of the “class”. He made a simplified design, in the Javascript language, the new command is followed not by the class, but by the constructor.
For example, there is now a constructor function called DOG that represents the prototype of a dog object.
1 | function DOG(name){ |
Using new on this constructor generates an instance of the dog object.
1 | Var dogA = new DOG ('big hair'); |
Note the constructor functionthis关键字, which represents the newly created instance object.
Disadvantages of the new operator
One disadvantage of using constructor functions to generate instance objects is that properties and methods cannot be shared.
For example, in the constructor function of the DOG object, set the common property species of an instance object.
1 | function DOG(name){ |
Then, generate two instance objects.
1 | Var dogA = new DOG ('big hair'); |
The species properties of these two objects are independent, and modifying one will not affect the other.
1 | dogA.species = 'Feline'; |
Each instance object has its own copy of properties and methods. This is not only unable to achieve data sharing, but also a great waste of resources.
Introduction of prototype property
With this in mind, Brendan Eich decided to set a prototype property for the constructor function.
This property contains an object (hereinafter referred to as the “prototype object”), and all the properties and methods that instance objects need to share are placed in this object; those that do not need to be shared are placed in the constructor function.
Once the instance object is created, it will automatically reference the properties and methods of the prototype object. That is, the properties and methods of the instance object are divided into two types, one is local and the other is referenced.
Or take the DOG constructor function as an example, and now rewrite it with the prototype property.
1 | function Dog(name) { |
Now, the species property is placed in the prototype object and is shared by the two instance objects. As long as the prototype object is modified, it will affect both instance objects at the same time.
1 | DOG.prototype.species = 'Feline'; |
Since all instance objects share the same prototype object, from the outside, the prototype object appears to be the prototype of the instance object, and the instance object appears to “inherit” the prototype object.
This is the design idea of JavaScript inheritance mechanism.
How JavaScript inherits
ES5
Prototype chain inheritance
1 | function Dog(name) { |
Principle:
Species is not a property on the dog instance, but proto, which is Dog.prototype, which is the property on the new animal () instance
Advantages:
Simple and easy to implement, new instances of the parent class and attribute subclasses can access
Disadvantages:
Instance properties can be added in the subclass. If you want to add new prototype properties and methods, you need to add them after the new parent class constructor function
Multiple inheritance cannot be achieved
When creating a subclass instance, parameters cannot be passed to the parent class constructor
Borrowing constructor function inheritance
1 | function Dog(name) { |
Principle:
Species is on the dog instance, because when new Dog () calls the Animal.call method, this is the latter dog instance, so in fact, the Animal method is called in the context of dog, that is to say, when Animal is executed, the context is dog, and the species attribute is directly hung on dog
Count is mounted on the dog instance when executing setCount.
Advantages:
Resolved subclass constructor passing parameters to parent class constructor
Multiple inheritance (call or apply multiple parent classes) can be implemented.
Disadvantages:
Methods are defined in constructor functions and cannot be used to reuse
Cannot inherit prototype properties/methods, only instance properties and methods of parent classes can be inherited
Prototype inheritance (instance inheritance)
1 | function Dog(name) { |
Principle:
The dog here is actually an instance of Animal, not an instance of Dog, that is, dog instanceof Dog is false.
This method is to first create an Animal instance and then create new properties on the instance.
Advantages:
Unlimited calling method
Simple and easy to implement
Disadvantages: Cannot inherit multiple times
Combined inheritance
Call the parent class constructor function, inherit the properties of the parent class, and use the parent class instance as a subclass prototype to realize the function to reuse
1 | function Animal(species) { |
Principle:
Use constructor function inheritance to create properties for each subclass instance, which means that properties on each subclass are exclusive.
Use prototype chain inheritance to share methods on parent class prototypes.
Disadvantages:
Since the parent class was called twice, two instances are generated
Advantages:
Functions to reuse
There is no reference attribute problem
Can inherit properties and methods, and can inherit properties and methods of prototypes
Parasitic combined inheritance
1 | //parent class |
Principle:
On the basis of combined inheritance, the idea of parasitic inheritance is used to transform the prototype chain inheritance method, because the prototype chain inheritance method will create an instance of the parent class again, which will cause a waste of memory, so an empty class is created, and then The prototype object of the empty class is set as the prototype object of the parent class, and then the proto of the subclass points to an instance of the empty class.
ES6
1 | //class is equivalent to the constructor function in es5 |
** Difference between ES5 Inheritance and ES6 Inheritance **
Es5 inheritance first creates its own this pointer in the subclass, and finally adds the method to this
Child.prototype=new Parent() || Parent.apply(this) || Parent.call(this)
Es6 inheritance is to use the keyword to first create an instance object of the parent class this, and finally modify this in the subclass class.
Reference link
https://zhuanlan.zhihu.com/p/37735247
http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html