The original address: https://github.com/catchonme/blog/issues/3

We know that one of the biggest benefits of Class is the ability to implement inheritance, so that subclasses can reuse as much code as possible by inheriting from their parent Class.

So here’s the question

  • How to implement subclasses to inherit the attributes and functions of their parent classes,
  • When a subclass inherits from a parent class, why doesn’t the subclass’s function with the same name override the parent class’s function with the same name

We’ll look at prototype.js to see how ES5 implements Class

Prototype.js method for writing a Class

var Animal = Class.create({
  initialize: function(name) {
    this.name = name; }})var myAnimal = new Animal('jack'); 
console.log(myAnimal.name);// jack

var Cat = Class.create(Animal, {
  initialize: function($super, name, age) {$super(name);
    this.age = age; }})var myCat = new Cat('mia'.13); 
console.log(myCat.name); // mia
console.log(myCat.age); / / 13
Copy the code

Create Class: Create a Class using class. create. The initialize function initializes the Class properties

Inheritance: Subclasses pass in the name of the parent Class as the first argument to class.create, and $super as the first argument to the function. Within the function, $super(args) is used to call the function of the same name

Then we look at the prototype.js internal implementation Class. Here’s the rough structure. The body is three functions, including an empty function

var Class = (function(){
  var subclass() {}; / / empty function
  function create() { // code... } 
  function addMethods() { // code... }  
  return {
    create: create,
    Methods: {
      addMethods: addMethods
    }
  }  
})();
Copy the code

So let’s break it down, what does the create function do?

function create(a) {
  var parent = null, properties = [].slice.call(arguments);

  // If the first argument passed is a function, it is the parent of the current class
  if (isFunction(properties[0]))
    parent = properties.shift();

  // Create a klass function and execute initialize
  function klass(a) {
    this.initialize.apply(this, arguments);
  }

  // extend assigns class.methods attributes to klass
  extend(klass, Class.Methods);
  // Set the current class to parent
  klass.superclass = parent;
  klass.subclasses = [];

  // If the current class has a parent class, we need to assign the attributes and functions of the parent class to the current class
  if (parent) {
    // The prototype of the parent class is assigned to the empty function subclass.prototype
    subclass.prototype = parent.prototype;
    // Assign klass.prototype by instantiating subclass so that klass can have the attributes and functions of its parent class
    klass.prototype = new subclass;
    parent.subclasses.push(klass)
  }

  // addMethods assigns all parameters passed to Klass's prototype, which will be explained later
  for (var i=0, length=properties.length; i<length; i++) {
    klass.addMethods(properties[i]);
  }

  if(! klass.prototype.initialize) { klass.prototype.initialize = emptyFunction } klass.prototype.constructor = klass;return klass
}
Copy the code
  • createSo what does the function do
    • newklassFunction, executeinitializefunction
    • Determines if a parent class was passed in, and if so, assigns the attributes and functions of the parent class to the current class
    • useaddMethodsMethod to assign the user’s function toklassprototype

If the prototype function of the parent class has the same name as the function of the subclass, then add the function of the parent class to the prototype. Why wouldn’t it be covered?

Let’s look at the addMethods function

function addMethods(source) {
  var ancestor = this.superclass && this.superclass.prototype,
      properties = Object.keys(source);

  // Iterate over the passed functions, assigning each to the current prototype
  for (var i=0, length=properties.length; i<length; i++) {
    var property = properties[i], value = source[property];

    // Check whether the first argument is $super
    if (ancestor && isFunction(value)
        && value.argumentNames()[0] = ="$super") {

      var method = value;

      // This is the key to why subclasses can execute functions of the same name as their parent classes
      value = (function (m) {
        return function () {
          The parent class executes the function of the same name once by passing the function name to the parent class, then
          return ancestor[m].apply(this.arguments);
        }
      })(property).wrap(method); // wrap(method) executes the function of the same name of the current class again

      // Override valueOf of the current function
      value.valueOf = (function (method) {
        return function () {
          return method.valueOf.call(method);
        }
      })(method);

      // Override toString for the current function
      value.toString = (function (method) {
        return function () {
          return method.toString.call(method);
        }
      })(method);
    }

    // Assign the function to the prototype of the current class
    this.prototype[property] = value; }}Copy the code
  • addMethodsWhat did you do?
    • Iterate over the function passed
      • If the first argument to the function is$superCall the parent function with the same name once, and call the current class function with the same name once, so that can be implemented$superThe function of the parent class is called
      • If the function’s first argument is not$super, directly assigned to the current classprototype

The other utility functions used in the above functions, such as isFunction, extend, etc., are annotated in more detail by clicking here, since I have separated the prototype Class from js.

So let’s go back to the original question

  • How do I inherit attributes and functions from a parent class?
    • That instantiates the parent function through an intermediate variable and then assigns it to the child functionprototypeIn this case, the function has the attributes and functions of the parent function
  • Why don’t subclasses overwrite functions of the same name as their parent class?
    • Subfunctions set propertiessuperclassIs the parent function assigned to the current class by all custom functions in the current classprototype, will passsuperclassFind the function with the same name of the parent class, so that when executing the function with the same name of the parent class, the function with the same name of the child class is executed once, and the function with the same name of the child class is executed once.