introduction
In the June update, I talked about JS object creation and object inheritance in a random way. Some workers still expressed doubts about this. Please note: these are two different but related things, don’t mess it up!
These articles are:
Looking back, the design pattern of "factory, structure, prototype" is in the dim lights
JS essence, "prototype chain inheritance and constructor inheritance"
"Factory, Construction, Prototype" design pattern and JS inheritance
JS Advanced Programming 4: The Focus of Class Inheritance
JS class is not just simple syntactic sugar!
This article is a summary, let’s find out! ! Toss toss
Object creation
It is not difficult to find that each article cannot be separated from at least one of the three design patterns: factory, structure, and prototype!
It makes people wonder: Why does JS have to use these three design patterns? ?
For the original traceability, we start with object creation:
We were used to declaring objects like this (without any design pattern)
let car= { price:100, color:"white", run:()=>{("run fast")} }
When there are two or more such objects that need to be declared, it is impossible to copy and write them all the time:
let car1 = { price:100, color:"white", run:()=>{("run fast")} } let car2 = { price:200, color:"balck", run:()=>{("run slow")} } let car3 = { price:300, color:"red", run:()=>{("broken")} }
Write this way:
- It's troublesome to write, and the repetitive code is large;
- It is not conducive to modification. For example, when a car object needs to add, delete and modify a property, it needs to add, delete and modify multiple places;
Factory functions
It must be encapsulated. The first reaction can be done by using functions to help us create objects in batches~
So:
function makeCar(price,color,performance){ let obj = {} = price = color = ()=>{(performance)} return obj } let car1= makeCar("100","white","run fast") let car2= makeCar("200","black","run slow") let car3= makeCar("300","red","broken")
This is the origin of the factory design pattern when creating objects in JS~
At this point, it should be enough for [Object Creation], right? Yes, it's basically enough without considering expansion.
But at this time, a new requirement is needed to create car4, car5, and car6 objects. They need to add another new one on the original basis.brand
How do you write attributes?
First reaction, modify directlymakeCar
function makeCar(price,color,performance,brand){ let obj = {} = price = color = ()=>{(performance)} = brand return obj } let car4= makeCar("400","white","run fast","benz") let car5= makeCar("500","black","run slow","audi") let car6= makeCar("600","red","broken","tsl")
If you write this way, it will affect the original car1, car2, and car3 objects;
Then write another onemakeCarChild
Is the factory function OK?
function makeCarChild (price,color,performance,brand){ let obj = {} = price = color = ()=>{(performance)} = brand return obj } let car4= makeCarChild("400","white","run fast","benz") let car5= makeCarChild("500","black","run slow","audi") let car6= makeCarChild("600","red","broken","tsl")
It is OK, but it is too troublesome. It seems too stupid to copy the previous attributes and establish N similar factories. . .
Constructor
Therefore, in the factory design model, a constructor design model has been developed to solve the above problem of reuse (that is, inheritance).
function MakeCar(price,color,performance){ = price = color = ()=>{(performance)} } function MakeCarChild(brand,...args){ (this,...args) = brand } let car4= new MakeCarChild("benz","400","white","run fast") let car5= new MakeCarChild("audi","500","black","run slow") let car6= new MakeCarChild("tsl","600","red","broken")
The constructor is different from the factory function:
- The initial letter of the function name is usually capitalized;
- When creating objects, you need to use the new keyword (the process of new is not described here, as mentioned in the previous article);
- The function does not return, but uses this binding to find properties;
So far, the reuse of factory functions has also been solved.
Construction + Prototype
The new problem is that we cannot find MakeCar from MakeCarChild by looking for prototype chains
car4.__proto__=== // true .__proto__ === // false MakeCarChild.__proto__ === // false
No matter how you look at the prototype chain, you can't get it fromMakeCarChild
turn upMakeCar
This means: a subclass cannot inherit the properties on the parent class prototype
Here is a question of thinking: Why is it important to "find from the prototype chain"? Why do "subclasses inherit attributes on parent class prototype"? Can't it be possible to rely on this binding?
Therefore, the [Combination Inheritance] of the constructor design pattern + the prototype design pattern came into being
function MakeCar(price,color,performance){ = price = color = ()=>{(performance)} } function MakeCarChild(brand,...args){ (this,...args) = brand } = new MakeCar() // The prototype inherits the constructor of the parent class = MakeCarChild // Reset constructorlet car4= new MakeCarChild("benz","400","white","run fast")
Now look for the prototype, and you can find it:
car4.__proto__ === // true .__proto__ === // true
In fact, if you can get here, you are already very good. You have everything you should have, and the writing style is not very complicated.
Factory + Construction + Prototype
But there are always people who are pursuing the ultimate.
The above combination inheritance, the parent class constructor is called twice, once the call process, and the other is the prototype inheritance of new process. If it is called repeatedly every time it is instantiated, it is definitely not advisable. How to avoid it?
Factory + Construction + Prototype = Parasitic Combination Inheritance Comes into the times
The core is to create a new middleman F( ) through the factory function, copy a prototype object of the parent class, and then assign it to the prototype of the subclass;
function object(o) { // Factory function function F() {} = o; return new F(); // new An empty function takes up very little memory} function inherit(child, parent) { // Prototype inheritance var prototype = object() = child = prototype } function MakeCar(price,color,performance){ = price = color = ()=>{(performance)} } function MakeCarChild(brand,...args){ // Constructor (this,...args) = brand } inherit(MakeCarChild,MakeCar) let car4= new MakeCarChild("benz","400","white","run fast")
car4.__proto__ === // true .__proto__ === // true
ES6 class
Later, ES6's class inherits syntactic sugar as a parasitic combination:
class MakeCar { constructor(price,color,performance){ = price = color =performance } run(){ (()) } } class MakeCarChild extends MakeCar{ constructor(brand,...args){ super(brand,...args); = brand; } } let car4= new MakeCarChild("benz","400","white","run fast")
car4.__proto__ === // true .__proto__ === // true
Interested coworkers can check out the code parsed by ES6 into ES5: Prototype and Prototype Chain - The underlying implementation principle of ES6 Class #22
Objects and functions
Finally, I would like to talk about the relationship between JS objects and functions:
Even if an object is declared like this,let obj = {}
, it is also constructed by the constructorObject
Constructed from:
let obj = {} obj.__proto__ === // true
In JS, everything is an object, the object is constructed from a function, and the function itself is an object.
The meaning in the corresponding code:
- The implicit prototypes of all constructors are equal to the display prototype of Function. Functions are constructed from Function, and the Object constructor is no exception;
- The implicit prototype of the display prototype of all constructors is equal to the display prototype of Object, and Function is no exception;
// 1. Object.__proto__ === // true // 2. .__proto__ === // true
This design is really speechless, entangled, and trouble. . .
You can only remember first according to the wrong understanding mentioned before: Function is God, God created all things; Object is all things. All things are created by God (objects are constructed by functions), and God himself belongs to a kind of matter (the function itself is also an object);
For this article, inheritance is actually inherited by the parent-child constructor, and then the constructor instantiates the object to realize the inheritance of the object.
Who is inheriting it? function? Object? All are~~
summary
This article starts with creating an object and talks about factory functions, which can be used as the most basic encapsulation;
Then, the expansion of the factory evolves into a constructor;
Then, based on the characteristics of the prototype, construct + prototype, and obtain combination inheritance;
When pursuing the ultimate, we talk about parasitic combinations;
Let’s talk about the Es6 class that simplifies writing;
And finally thinking about objects and functions.
For more information about JS object creation and inheritance, please follow my other related articles!