编程人 cdmana.com

JavaScript inheritance

Class inheritance

// Declare the parent class 
// Declare the parent class 
function SuperClass() {
   
   
  this.superValue = true;
}
// Add a shared method to the parent class 
SuperClass.prototype.getSuperValue = function () {
   
   
  return this.superValue;
};

// Declaring subclasses 
function SubClass() {
   
   
  this.subValue = false;
}

// Inherited parent class 
SubClass.prototype = new SuperClass();
// Add common methods to subclasses 
SubClass.prototype.getSubValue = function () {
   
   
  return this.subValue;
};

var instance = new SubClass();
console.log(instance.getSuperValue()); //true
console.log(instance.getSubValue()); //false

Class inheritance needs to assign the instance of the parent class to the prototype of the child class , subClass.prototype Inherited superClass.
This kind of class inheritance has two disadvantages . firstly , Because subclasses pass through prototypes prototype Instantiate the parent class , Inherited the parent class , A common property in a parent class is a reference type , It will be shared by all instances in the subclass , Therefore, if an instance of a subclass changes the common properties inherited by the subclass prototype from the parent class constructor, it will directly affect other subclasses , as follows :

function SuperClass() {
   
   
    this.courses = [' Chinese language and literature ', ' mathematics ', ' English ']
}
function SubClass() {
   
   }
SubClass.prototype = new SuperClass();

var instance1 = new SubClass()
var instance2 = new SubClass()

console.log(instance2.courses) //[' Chinese language and literature ', ' mathematics ', ' English ']
instance1.courses.push(' chemical ')
console.log(instance2.courses) //[' Chinese language and literature ', ' mathematics ', ' English ', ' chemical ']

instance1 The revision of the instance2, It's a disaster trap . second , Because the inheritance of subclass implementation depends on its prototype prototype Implementation of instantiation of parent class , So when you create a parent class , Cannot pass parameters to a parent class , Therefore, when instantiating the parent class, the properties in the parent class constructor cannot be initialized . How to solve this problem ? Please read on .

Constructor inheritance

function SuperClass(current) {
   
   
  this.courses = [" Chinese language and literature ", " mathematics ", " English "];
  this.current = current;
}

// The parent class declares the prototype method 
SuperClass.prototype.getCourses= function () {
   
   
  console.log(this.courses);
};

// Declaring subclasses 
function SubClass(current) {
   
   
  SuperClass.call(this, current);
}

var instance1 = new SubClass(" Chinese language and literature ");
var instance2 = new SubClass(" mathematics ");

instance1.courses.push(' chemical ')
console.log(instance1.courses); //[" Chinese language and literature ", " mathematics ", " English ", " chemical "]
console.log(instance1.current); // Chinese language and literature 
console.log(instance2.courses); //[" Chinese language and literature ", " mathematics ", " English "]
console.log(instance2.current); // mathematics 

instance1.getCourses() //TypeError: instance1.getCourses is not a function

SuperClass.call(this, current) This statement is the essence of constructor inheritance . because call This method can change the context of the function , So in subclasses , Yes SuperClass Call this call That is to execute the variables in the subclass in the parent class , Because the parent class is for this Binding properties , Therefore, the subclass inherits the common properties of the parent class .
Because this type of inheritance does not involve prototypes prototype, So the prototype method of the parent class is not inherited by the subclass , To be inherited by subclasses , Can only be showCourse In the parent constructor , But this violates the principle of code reuse . In order to combine the advantages of the above two kinds of inheritance , So there's combinatorial inheritance .

Combination inheritance

// Combination inheritance 

function SuperClass(current) {
   
   
  // Reference types have common properties 
  this.courses = [" Chinese language and literature ", " mathematics ", " English "];
  //  Value types share properties 
  this.current = current;
}

SuperClass.prototype.getCourses = function () {
   
   
  console.log(this.courses);
};

SuperClass.prototype.getCurrent = function () {
   
   
  console.log(this.current);
};

//  Declaring subclasses 
function SubClass(current, time) {
   
   
  // The constructor inherits the properties of the parent class 
  SuperClass.call(this, current);
  this.time = time;
}
// Class inheritance   Subclass prototype inherits parent class 
SubClass.prototype = new SuperClass();
// Subclass prototype method 
SubClass.prototype.getTime = function () {
   
   
  console.log(this.time);
};

Execute the parent class constructor in the subclass constructor , Instantiating a parent class on the prototype of a subclass is a composite pattern , Change the reference type properties inherited from the parent class in the subclass instance courses It doesn't change other instances , Test the following

var instance1 = new SubClass(" Chinese language and literature ", "9:00");
instance1.getTime(); //9:00
instance1.courses.push(' chemical ')
instance1.getCourses(); //[" Chinese language and literature ", " mathematics ", " English ", " chemical "]
instance1.getCurrent(); // Chinese language and literature 
console.log(instance1.current)// Chinese language and literature 

var instance2 = new SubClass(" mathematics ", "10:00");
instance2.getTime(); //10:00
instance2.getCourses(); //[" Chinese language and literature ", " mathematics ", " English "]
instance2.getCurrent(); // mathematics 
console.log(instance2.current)// mathematics 

But the pattern executes the parent class function once while executing the subclass constructor , In the implementation of subclass prototype inheritance, the parent class constructor is executed again , Called the parent class constructor twice , It's obviously a design flaw , Is there a better way ? For this defect , There is “ Parasitic combinatorial inheritance ”

Parasitic combinatorial inheritance

Before introducing this way of inheritance , You need to know “ Original pattern inheritance ” and “ Parasitic inheritance ”

Basic understanding

Original pattern inheritance

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

var course = {
   
   
  name: " Chinese language and literature ",
  alikeCourse: [" mathematics ", " English "],
};

var newCourse = inheritObject(course);
newCourse.name = " chemical ";
newCourse.alikeCourse.push(" Physics ");

var otherCourse = inheritObject(course);
otherCourse.name = " Politics ";
otherCourse.alikeCourse.push(" history ");

console.log(newCourse.name); // chemical 
console.log(newCourse.alikeCourse); //[" mathematics ", " English ", " Physics ", " history "]

console.log(otherCourse.name); // Politics 
console.log(otherCourse.alikeCourse); //[" mathematics ", " English ", " Physics ", " history "]

console.log(course.name); // Chinese language and literature 
console.log(course.alikeCourse); //[" mathematics ", " English ", " Physics ", " history "]

inheritObject It can be seen as an encapsulation of class inheritance , The transition class F Equivalent to a subclass in class inheritance . The problem of common reference types in class inheritance still exists , But over class F Nothing in the constructor , So it costs less .

Parasitic inheritance

“ Parasitic inheritance ” Is in “ Original pattern inheritance ” On this basis, we will continue to strengthen .

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

var course = {
   
   
  name: " Chinese language and literature ",
  alikeCourse: [" mathematics ", " English "],
};

function createCourse(obj) {
   
   
  // Creating new objects through prototype inheritance 
  var o = new inheritObject(obj);
  //  Expand new objects 
  o.getName = function () {
   
   
    console.log(this.name);
  };
  return o;
}

const newCourse = createCourse(course)

In this way, attributes continue to grow inside an object , Like parasitic growth , So it's called parasitic inheritance . Parasitic inheritance is a secondary encapsulation of prototype inheritance , And in the process of secondary encapsulation, the inherited objects are expanded , In this way, the newly created object does not only have properties and methods in the parent class , And new properties and methods have been added . On the basis of this idea , Combined with combinatorial inheritance , Derived from “ Parasitic combinatorial inheritance ”

Realization

function inheritObject(o) {
   
   
    function F() {
   
   }
    F.prototype = o;
    return new F();
  }
function inheritPrototype(subClass, superClass) {
   
   
    // Make a copy of the prototype of the parent class and save it in the variable 
    var p = inheritObject(superClass.prototype)
    // Fixed subclass because of rewriting subclass prototypes constructor Property is modified 
    p.constructor = subClass
    // Set the prototype of the subclass 
    subClass.prototype = p
}

Save a copy of the above parent prototype , Assign values to subclass prototypes , So that inheritance , And the parent function is not called again , Test the following , Similar to the pattern of combinatorial inheritance

//test

function SuperClass(current) {
   
   
  // Reference types have common properties 
  this.courses = [" Chinese language and literature ", " mathematics ", " English "];
  //  Value types share properties 
  this.current = current;
}

SuperClass.prototype.getCourses = function () {
   
   
  console.log(this.courses);
};

SuperClass.prototype.getCurrent = function () {
   
   
  console.log(this.current);
};

//  Declaring subclasses 
function SubClass(current, time) {
   
   
  // The constructor inherits the properties of the parent class 
  SuperClass.call(this, current);
  this.time = time;
}

// Parasitic inheritance   Subclass prototype inherits parent class 
inheritPrototype(SubClass, SuperClass);

// Class inheritance   Subclass prototype inherits parent class 
// SubClass.prototype = new SuperClass();

// Subclass prototype method 
SubClass.prototype.getTime = function () {
   
   
  console.log(this.time);
};

var instance1 = new SubClass(" Chinese language and literature ", "9:00");
var instance2 = new SubClass(" mathematics ", "10:00");

instance1.getTime(); //9:00
instance1.courses.push(" chemical ");
instance1.getCourses(); //[" Chinese language and literature ", " mathematics ", " English ", " chemical "]
instance1.getCurrent(); // Chinese language and literature 
console.log(instance1.current); // Chinese language and literature 

instance2.getTime(); //10:00
instance2.getCourses(); //[" Chinese language and literature ", " mathematics ", " English "]
instance2.getCurrent(); // mathematics 
console.log(instance2.current); // mathematics 

The only difference is

// Parasitic inheritance   Subclass prototype inherits parent class 
inheritPrototype(SubClass, SuperClass);

// Class inheritance   Subclass prototype inherits parent class 
// SubClass.prototype = new SuperClass();

So that multiple subclasses and multiple instances do not affect each other , The parent constructor is called only once , Worthy of JavaScript The ultimate model of inheritance .

Scroll to Top