Writing in the front

  • conceptIf you have a way of giving one object access to properties or methods in other objects, we call this way inheritance.
  • backgroundSome objects have methods that are functions (functions are also objects), and it would be a waste of memory to declare these methods in constructors

// Equivalence relation
Person === Person.prototype.constructor
person1.__proto__ === person2.__proto__ === Person.prototype

Person.prototype === Person.prototype.constructor.prototype

Constructor since the prototype object for the person1 instance is Person.prototype, all person1 inherits constructor and all can access it
person1.__proto__ === person1.constructor.prototype

Copy the code

Note that JS inheritance is built on the premise that methods are created on prototypes and properties are created on instances

1. Prototype chain inheritance

Implementation: make the prototype of the subclass object point to the instance object of the parent class; That is, using an instance object of the parent class to override the prototype object of the subclass

Prototype chain inheritance diagram:

Note: Since the constructor property of subtype. prototype was overridden to point to SuperType, instance.constructor also points to SuperType


/ / sample:
function Parent() {
   this.isShow = true
   this.info = {
       name: "yhd".age: 18}; } Parent.prototype.getInfo =function() {
   console.log(this.info);
   console.log(this.isShow); // true
}

function Child() {};
Child.prototype = new Parent();

let Child1 = new Child();
Child1.info.gender = "Male";
Child1.getInfo();  // {name: "yhd", age: 18, gender: "male "}

let child2 = new Child();
child2.getInfo();  // {name: "yhd", age: 18, gender: "male "}
child2.isShow = false

console.log(child2.isShow); // false
console.log(child1.isShow); // true because when an instance assigns a non-reference property with the same name as the stereotype, the instance creates its own property with the same name
Copy the code
1.Advantages: Methods of the parent class can be reused2.Disadvantages: - All reference attributes (info) of the parent class are shared by all subclasses, changing the reference attributes of one subclass will affect the other subclasses - instances of subtypes cannot pass arguments to the parent type constructorCopy the code

Constructor inheritance

/ / sample:
function Parent(name) {
    this.info = { name: name };
}
function Child(name) {
    // inherits from Parent and passes the parameter
    Parent.call(this, name);
    
     // Instance properties
    this.age = 18
}

let child1 = new Child("yhd");
console.log(child1.info.name); // "yhd"
console.log(child1.age); / / 18

let child2 = new Child("wxb");
console.log(child2.info.name); // "wxb"
console.log(child2.age); / / 18
Copy the code
1.Advantages :(fixed stereotype chain inheritance) - reference properties of the parent class are no longer shared by subclass instances - subclasses can pass arguments to the parent class2.Disadvantages: - Subclass instances can no longer access methods on the parent class stereotype (because there is no stereotype connection between the parent and subclass in constructor inheritance mode); Therefore, all method properties are written in the constructor, which is initialized each time an instance is created, resulting in a method for each instance, wasting memory.Copy the code

3. Combinatorial inheritance (combinatorial prototype chain inheritance and borrowed constructor inheritance) (common)

Composite inheritance combines the advantages of both stereotype chain inheritance and embeded constructor inheritance (constructor inheritance)

The basic idea is to use a stereotype chain to inherit properties and methods from the stereotype and a constructor to inherit instance properties, so that methods can be defined on the stereotype for reuse and each instance can have its own properties

/ / sample:
function Parent(age){
    this.colors = ['red'.'yellow']
    this.age = age
}

function Son(age, name){
    // Advantages: Subclasses can pass arguments to the parent class, and the reference attribute subclasses in the parent class are guaranteed not to share, because call passes this to each subclass
    Parent.call(this, age)
    this.name = name
}

Parent.prototype.getAge = function(){
    console.log(this.age+The '-'+this.name)
    console.log(this.colors)
}

// This step allows Son and Parent to have prototype contact, and subclass instances can call methods of the Parent class's prototype
// But this step also results in a colors on son.prototype
Son.prototype = new Parent()

let son1 = new Son(18.'John')
let son2 = new Son(20.'Bob')

son1.colors.push('pink')

son1.getAge() // 18--John ['red', 'yellow', 'pink']
son2.getAge() // 20--Bob ['red', 'yellow']
Copy the code

One problem is that colors has a copy on the prototype and a copy on the instance object of the subclass

1.Advantages :(makes up for the disadvantages of stereotype chain inheritance and constructor inheritance, and adopts the advantages of both) - methods on the superclass stereotype can be reused - subclasses can pass arguments to the superclass - reference properties in the superclass constructor are not shared2.Disadvantages: - Called the superclass constructor twice (memory) : once while creating the subtype stereotype and once inside the subtype constructor - the subclass object has its own reference attribute colors, and the stereotype object has a copy of the colors attributeCopy the code

4. Original type inheritance

Background: The starting point is that you can use stereotypes to share information between objects without custom types. Hence the following object function. Saves the step of creating custom types (which feels pointless)

Usage scenario: Primitive inheritance is perfect for just wanting one object to inherit from another, without having to define additional constructors outside of it.

/ / sample:
function object(o){
    function F(){}
    F.prototype = o
    return new F()
}

let person = {
    name: Linghu Chong.colors: ['red'.'yellow']}// The shared method on the prototype
person.say = function(){
    console.log(this.name)
}
let p1 = object(person)
let p2 = object(person)
p1.colors.push('pink')
p1.name = 'Whatever I do'
p2.colors.push('blue')

console.log(p1.name+' '+p1.colors)	// Red,yellow,pink,blue
console.log(p2.name+' '+p2.colors)	// Linghu Chong red,yellow,pink,blue
Copy the code
1.Advantages: - Common prototyping methods2.Disadvantages: - Stereotype reference attributes are shared - subclasses cannot pass arguments to their parent classCopy the code

ECMAScript 5 normalizes the concept of type-inheritance by adding the object.create () method. This method takes two parameters: the object to be the prototype for the new object and, optionally, the object to define additional properties for the new object. With only one argument, object.create () has the same effect as the Object () method here.

The second argument to Object.create() is the same as the second argument to Object.defineProperties() : each new property is described by its own descriptor. Attributes added in this way overshadow attributes of the same name on the prototype object

/ / sample:
let person = {
    name: Linghu Chong.colors: ['red'.'yellow']}let p1 = Object.create(person, {
    name: {
        value: 'Jiu Mozhi'}})console.log(p1.name)	/ / dove the think tank

Copy the code

Parasitic inheritance

Parasitic inheritance is an enhanced version of the original type inheritance.

function object(o){
    function F(){}
    F.prototype = o
    return new F()
}

function createAnother(origin){
  var clone=object(origin);
  // enhance the object, bind the method to the object; However, this method is not bound to the prototype, but to the instance, and each instance has a copy of the SAY method
  clone.say=function(){
    alert(this.name)
  }
  return clone;
}


let person = {
    name: Linghu Chong.colors: ['red'.'yellow']}let p1 = createAnother(person)
let p2 = createAnother(person)
p1.colors.push('pink')
p1.name = 'Whatever I do'
p2.colors.push('blue')

console.log(p1.name+' '+p1.colors)	// Red,yellow,pink,blue
console.log(p2.name+' '+p2.colors)	// Linghu Chong red,yellow,pink,blue
console.log(p1.say())	/ / as I can
console.log(p2.say())	/ / make fox blunt
Copy the code
/ / the pros and cons
1.Advantages: - There is no additional creation of custom type code, instead it will be custom type code`function F(){}`The whole package is carried out2.Disadvantages: - Each object has its own say method, resulting in a waste of memory - stereotype reference types are sharedCopy the code

6. Parasitic combinatorial inheritance (common)

Parasitic combination inheritance can be regarded as the best mode of reference type inheritance. Parasitic combinatorial inheritance == Parasitic + combinatorial inheritance

Prototype = new Parent(); the Parent constructor is called twice, and there is a reference type on the Child’s prototype object.

What if instead of using child.prototype = new Parent(), we indirectly call child.prototype to Parent. Prototype?

// Combination mode +3 lines of code adaptation
function Parent (name) {
    this.name = name;
    this.colors = ['red'.'blue'.'green'];
}

Parent.prototype.getName = function () {
    console.log(this.name)
}

function Child (name, age) {
    Parent.call(this, name);
    this.age = age;
}

Prototype = new Parent()
// Use 'empty F' as the intermediate join point between Parent and subclass, so there are no combinatorial drawbacks (add unnecessary redundant attributes to child.prototype, and reduce the number of calls to Parent())
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F();
///

var child1 = new Child('kevin'.'18');

console.log(child1);
Copy the code

// Parasitic combinatorial inheritance

function object(obj) {
  function Fun() {}; Fun.prototype = obj;return new Fun();
}
// The core logic of parasitic combinational inheritance: create an empty object between the subclass and the parent class, forming a chain of archetypes
function inheritPrototype(child, parent) {
  let tempObj = object(parent.prototype);
  // Set constructor manually since we are rewriting the prototype below
  tempObj.constructor = child;
  child.prototype = tempObj;
}

function Parent(name) {
  this.name = name;
  this.friends = ["rose"."lily"."tom"]
}

Parent.prototype.sayName = function () {
  console.log(this.name);
}

function Child(name, age) {
  Parent.call(this, name);
  this.age = age;
}

inheritPrototype(Child, Parent);
Child.prototype.sayAge = function () {
  console.log(this.age);
}

let child1 = new Child("yhd".23);
child1.sayAge(); / / 23
child1.sayName(); // yhd
child1.friends.push("jack");
console.log(child1.friends); // ["rose", "lily", "tom", "jack"]

let child2 = new Child("yl".22)
child2.sayAge(); / / 22
child2.sayName(); // yl
console.log(child2.friends); // ["rose", "lily", "tom"]
Copy the code
1.Advantages: - The Parent constructor is called only once - The Child can pass arguments to the Parent - the Parent method can be reused - the reference properties of the Parent are not sharedCopy the code

The reference series

Juejin. Cn/post / 691421…

www.cnblogs.com/ranyonsue/p…

Github.com/mqyqingfeng…