Introduction
As mentioned in the previous section, some people think JavaScript is not really an object-oriented language. In classic object-oriented languages, you might prefer to define class objects, then you can simply define which classes inherit which classes, JavaScript uses a different implementation, and inherited object functions are inherited not by copying, but by prototype chains (usually).It is called prototypal inheritance.
Inheritance Mode
When it comes to inheritance, you first have to understand what it is that you inherit.For ease of understanding, I personally classify attributes (including methods) into common and private attributes.Private attributes such as name or ID card are unique to everyone.Common attributes are attributes or methods that can be shared, such as hobby attributes, eating methods.
Inheritance of private properties (constructor + call)
This is simpler, private attributes use constructors and call s or apply
const Person = function (name) { this.name = name } const Students = function (name) { Person.call(this,name) } const xm = new Students('Xiao Ming') console.log(xm) //Students {name:'Xiao Ming'}
Inheritance of Public Properties
There are a few pits in it, so listen to me.
It's certainly true to inherit public attributes through a prototype chain, but when we design, there is a principle that subclasses need to have their own prototypes, and the parent must have its own prototypes, so that child instances can't find attributes on their own prototypes until they find them.
Subclass.prototype =parent class.prototype is certainly not possible. Although the method of the parent prototype can be inherited, the prototype of the subclass and the prototype of the parent class are the same. Adding a method to the prototype of the subclass is equivalent to adding a method to the prototype of the parent class.so we should have a buffer.
Subclass instances---->Subclass prototypes------->Intermediate objects--------->Parent prototypes//Accessible along arrows, behaving in accordance with our design principles
The most common is to use an instance of the parent class as this intermediate object.
Children.prototype = new Parent()
But there's something wrong with this.The parent class is instantiated once.If the parent class is particularly complex, such as axios, there is a lot of extra overhead.
Let's see what the intermediate object does, it actually only serves as an isolation and prototype redirection.You can do this with an empty object
//Implement Buffering var fn = function() {} fn.prototype = Parent.prototype Children.prototype = new fn()
In fact, this is the implementation of Oject.create()
//Oject.create() Object.create = function(obj){ var fn = funcion(){} fn.prototype = obj reurturn new fn() }
Ultimate Inheritance Solution
Now we have to inherit both private and public attributes.
const Person = function (name) { this.name = name } Person.prototype.eat = function () { console.log('i am hungry,i want to eat!') } const Student = function (name) { Person.call(this,name) } Student.prototype = Object.create(Person.prototype) //Watch out here!Sequelae of prototype redirection const xm = new Student ('Xiao Ming') xm.name //'Xiao Ming' xm.eat() //i am hungry,i want to eat! console.log(xm) //Student {name:'Xiao Ming'} // name:'Xiao Ming' // __proto__: Person // _u proto_u: //This layer is an empty object with only one u proto_u attribute pointing to the prototype of Person // eat: ƒ () // constructor: ƒ (name) // __proto__: Object
But here xm.constructor.name // Person
Here, because the construtor was not reset after the prototype redirection, the XM itself had no construtor and could only find the empty object we created, and the empty object had no construtor so it went up and found that the construtor on Person.prototype was Person
So the solution is simple, just reset the constructor when rewriting the prototype chain
... var temObj = Object.create(Person.prototype) temObj.constructor = Student Student.prototype =temObj ... xm.constructor.name // Student OK done
What did new do
Now that new has to be used in creating classes, let's talk about what new does.
1. Create an object o inheritance constructor
2. Make this of the constructor o and execute the constructor, setting the return value to k
3. If k
//Copy new function new1(func) { var o = Object.create(func.prototype) var k = func.apply(o,arguments[1]) return typeof k === 'object'? k: o } const x = new1(Student,['Zhang San']) x.name //'Zhang San' x.eat //'i am hungry,i want to eat!'
Let's go back and analyze constructor pattern inheritance
const Person = function (name) { this.name = name } const Students = function (name) { Person.call(this,name) //this is a student instance } const xm = new Students('Xiao Ming') //Analyze what's been done here console.log(xm) //Students {name:'Xiao Ming'}
1. Let the empty object o inherit Students(o has access to the Students prototype)
2.student executes, executes Person's code, this is o, and passing in name, o.name='Xiaoming'returns k as undefined
3. Return o, that is, {name:'Xiaoming'}
I wrote this today, but it's not over yet...