Principles of JavaScript classes and inheritance

(For the persevering there is no such thing as failure. - Bismarck)

insert image description here

class

Related Links

MDN link for
a detailed description of the class
Notes about constructors, prototypes and the prototype chain

class overview

A class is a template for creating objects. They encapsulate data with code to manipulate that data. Classes in JS are built on prototypes, but also have some syntax and semantics not shared with similar semantics of ES5 classes.
In fact, classes are "special functions", and just like function expressions and function declarations that you can define, class syntax has two components: class expressions and class declarations.

JavaScript object-oriented programming

Before es6, object-oriented programming was to create functions and instantiate constructors to achieve the goal, but this is very different from traditional object-oriented programming, such as c++ and java. Let's first understand the object-oriented programming of the following functions

function

Create a normal function animal

Ordinary functions can be used as function methods, directly perform business operations and return

const animal = function (name, color) {
    
    
  return `动物名称:${
      
      name} - 动物毛发颜色:${
      
      color}`
};
console.log(animal('刺猬', '褐色'));

Create a constructor Animal

A constructor is a special function, similar to traditional programming classes, which is mainly used to initialize objects, that is, to assign initial values ​​to object member variables. It is always used with new. We can extract some public properties and methods in the object, and then encapsulate them into this function.
The use of constructors requires attention to the following two points

  1. Constructors have the same meaning as traditional classes, with the first letter capitalized
  2. The constructor must be instantiated to make sense, that is, new

In the process of new, the following things are also done

  1. Create a new empty object in memory.
  2. Let this point to this new object.
  3. Execute the code in the constructor to add properties and methods to this new object.
  4. Return this new object (so no return inside the constructor).

The member properties of the constructor are further divided into static properties and instantiated properties.
Instantiated properties can only be accessed after instantiating the object, such as hedgehogData.
Static properties can be accessed without instantiating an object, such as height.

const Animal = function (name, color) {
    
    
  this.name = name;
  this.color = color;
  this.getAnimal = function () {
    
    
    return `动物名称:${
      
      this.name} - 动物毛发颜色:${
      
      this.color}`
  }
};
const hedgehog = new Animal('刺猬', '褐色');
const hedgehogData = hedgehog.getAnimal();
console.log(hedgehogData);
Animal.height = 50;
console.log(Animal.height);

extension constructor

If we want to extend the constructor in the future, we have reached the point where we can continue to write this.'method name'. But this is highly intrusive to the code, will cause the constructor to become more and more bloated, and will cause invalid memory to increase.

const Animal = function (name, color) {
    
    
  this.name = name;
  this.color = color;
  this.getAnimal = function () {
    
    
    return `动物名称:${
      
      this.name} - 动物毛发颜色:${
      
      this.color}`
  }
};
const hedgehog = new Animal('刺猬', '褐色');
const dog = new Animal('狗', '黑色');
console.log(hedgehog.getAnimal === dog.getAnimal); // false 每个实例化对象都有自己的内存地址

But JavaScript also has two features, prototype chain and prototype
. Explanation on prototype and prototype chain
We can expand by customizing the prototype, so that member properties can be defined in the constructor, and methods can be extended through the prototype.

const Animal = function (name, color) {
    
    
  this.name = name;
  this.color = color;
};
Animal.prototype.getAnimal = function () {
    
    
  return `动物名称:${
      
      this.name} - 动物毛发颜色:${
      
      this.color}`
}
const hedgehog = new Animal('刺猬', '褐色');
const dog = new Animal('狗', '黑色');
console.log(hedgehog.getAnimal === dog.getAnimal); // true 原型上的方法和属性由对象直接继承,也就是可以共享访问,所以为true 

inherit

Inheritance of functions
Through the above we have learned that if you still want to inherit functions, then there are the following ways

  1. inheritance prototype
  2. use call method inheritance
  3. Using the apply method to inherit
    the steps is cumbersome, and the later maintenance is complicated, and it is different from the traditional object-oriented programming method, which violates the concept of object-oriented programming.

class class

Based on the above problems, es6 has introduced a new specification for class syntactic sugar, which is closer to the traditional object-oriented programming method.

class Animal {
    
    
  constructor(name, color) {
    
    
    this.name = name;
    this.color = color;
  }
  getAnimal () {
    
    
    return `动物名称:${
      
      this.name} - 动物毛发颜色:${
      
      this.color}`;
  }
}
const hedgehog = new Animal('刺猬', '褐色');
const dog = new Animal('狗', '黑色');
console.log(hedgehog.getAnimal === dog.getAnimal); // true

class inheritance extends

The super keyword MDN super explanation is used

class Animal {
    
    
  constructor(name, color) {
    
    
    this.name = name;
    this.color = color;
  }
  getAnimal () {
    
    
    return `动物名称:${
      
      this.name} - 动物毛发颜色:${
      
      this.color}`;
  }
}
class Cat extends Animal {
    
    
  constructor(name, color) {
    
    
    super();
    this.name = name;
    this.color = color;
  }
}
const dog = new Animal('狗', '黑色');
const cat = new Cat('猫', '橙色');
console.log(cat.getAnimal()); // 动物名称:猫 - 动物毛发颜色:橙色
console.log(cat.getAnimal === dog.getAnimal); // true

The result of class compilation

The babel website can be edited online
We compile the above class code into the native commonjs specification of nodejs.
insert image description here

"use strict";

function _inheritsLoose(subClass, superClass) {
    
    
  subClass.prototype = Object.create(superClass.prototype);
  subClass.prototype.constructor = subClass;
  _setPrototypeOf(subClass, superClass);
}
function _setPrototypeOf(o, p) {
    
    
  _setPrototypeOf = Object.setPrototypeOf
    ? Object.setPrototypeOf.bind()
    : function _setPrototypeOf(o, p) {
    
    
        o.__proto__ = p;
        return o;
      };
  return _setPrototypeOf(o, p);
}
var Animal = /*#__PURE__*/ (function () {
    
    
  function Animal(name, color) {
    
    
    this.name = name;
    this.color = color;
  }
  var _proto = Animal.prototype;
  _proto.getAnimal = function getAnimal() {
    
    
    return "name:" + this.name + " - color:" + this.color;
  };
  return Animal;
})();
var Cat = /*#__PURE__*/ (function (_Animal) {
    
    
  _inheritsLoose(Cat, _Animal);
  function Cat(name, color) {
    
    
    var _this;
    _this = _Animal.call(this) || this;
    _this.name = name;
    _this.color = color;
    return _this;
  }
  return Cat;
})(Animal);
var dog = new Animal("dog", "black");
var cat = new Cat("cat", "orange");
console.log(cat.getAnimal());
console.log(cat.getAnimal === dog.getAnimal);

It can be seen that class is just syntactic sugar, the initialization of its class is actually a constructor, and the interior of extends is still the inheritance of the prototype.

Compared

Through the comparison of native functions and classes, the writing method of class syntactic sugar is closer to the traditional object-oriented programming method, and it is easier to develop than native functions and facilitate later maintenance.

How to implement multiple inheritance

Traditional object-oriented programming languages ​​only use single inheritance, because inheritance can improve development efficiency, program performance, and code reuse in most business scenarios. However, in the case of complex business and huge projects, somedefect

  1. The coupling between parent and child classes is too high, and changes in the parent class directly affect the child class.
  2. The flexibility of the subclass is reduced, and some subclasses in the parent class do not need or conflict with the attributes or methods of the subclass
  3. When the properties or methods of the parent class change, the subclass also needs to be changed. In severe cases, the subclass needs to be refactored
  4. ...
    Of course, some business scenarios do require multiple inheritance, but classes do not support multiple inheritance, and only one parent class can be written after extends.
    But we can achieve the purpose of multiple inheritance through native prototypes.
function more_father () {
    
    
  this.f_name = "父亲";
  this.f_age = 55;
  this.f_address = "北京朝阳"
};

more_father.prototype.f_method = function () {
    
    
  return this.f_name + this.f_age + this.f_address;
};

function more_mother () {
    
    
  this.m_name = "母亲";
  this.m_age = 53;
  this.m_address = "北京朝阳";
};

more_mother.prototype.m_method = function () {
    
    
  return this.m_name + this.m_age + this.m_address;
};


function more_son () {
    
    
  this.s_name = "孩子";
  this.s_age = 22;
  this.s_address = "北京朝阳"
};

more_son.prototype.s_method = function () {
    
    
  return this.s_name + this.s_age + this.s_address;
};

more_son.prototype.f_pro = new more_father();
more_son.prototype.m_pro = new more_mother();
const _mores = new more_son();
console.log(_mores.f_pro.f_method());

Guess you like

Origin blog.csdn.net/qq_42427109/article/details/130521357