Home  >  Article  >  Web Front-end  >  Introducing a simple JavaScript class framework_Basic knowledge

Introducing a simple JavaScript class framework_Basic knowledge

WBOY
WBOYOriginal
2016-05-16 15:52:571081browse

When writing the work-in-progress JavaScript book, I spent a considerable amount of time on the JavaScript inheritance system, and in the process studied various different solutions for simulating classic class inheritance. Among these technical solutions, the implementation of base2 and Prototype is the one I admire most.

From these solutions, a framework with its ideological connotation should be extracted. The framework must be simple, reusable, easy to understand, and independent of dependencies. Simplicity and usability are the key points. Here are usage examples:

var Person = Class. extend ( {
 init: function (isDancing ) {
  this. dancing = isDancing;
 },
 dance: function ( ) {
  return this. dancing;
 }
} );
var Ninja = Person.extend({
 init: function(){
  this._super( false );
 },
 dance: function(){
  // Call the inherited version of dance()
  return this._super();
 },
 swingSword: function(){
  return true;
 }
});
var p = new Person(true);
p.dance(); // => true
var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true
// Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class

There are a few things to note:

  • The constructor must be simple (implemented through the init function),
  • The newly defined analogy must inherit from the existing class,
  • All ‘classes’ inherit from the ancestor class: Class, so if you want to create a brand new class, the class must be a subclass of Class,
  • The most challenging point: the overridden method of the parent class must be accessible (through the configuration context).
  • In the above example, you can find that the init() and dance() methods of the Person parent class are called through this._super().

Quite happy with the results: made the class definition structured, kept single inheritance, and was able to call superclass methods.

Simple class creation and inheritance

The following is its implementation (easy to read and has comments), about 25 lines. Suggestions are welcome and appreciated.

/* Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */
// Inspired by base2 and Prototype
( function ( ) {
 var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
 // The base Class implementation (does nothing)
 this.Class = function(){};
  
 // Create a new Class that inherits from this class
 Class.extend = function(prop) {
  var _super = this.prototype;
   
  // Instantiate a base class (but only create the instance,
  // don't run the init constructor)
  initializing = true;
  var prototype = new this();
  initializing = false;
   
  // Copy the properties over onto the new prototype
  for (var name in prop) {
   // Check if we're overwriting an existing function
   prototype[name] = typeof prop[name] == "function" &&
    typeof _super[name] == "function" && fnTest.test(prop[name]) ?
    (function(name, fn){
     return function() {
      var tmp = this._super;
       
      // Add a new ._super() method that is the same method
      // but on the super-class
      this._super = _super[name];
       
      // The method only need to be bound temporarily, so we
      // remove it when we're done executing
      var ret = fn.apply(this, arguments);    
      this._super = tmp;
       
      return ret;
     };
    })(name, prop[name]) :
    prop[name];
  }
   
  // The dummy class constructor
  function Class() {
   // All construction is actually done in the init method
   if ( !initializing && this.init )
    this.init.apply(this, arguments);
  }
   
  // Populate our constructed prototype object
  Class.prototype = prototype;
   
  // Enforce the constructor to be what we expect
  Class.prototype.constructor = Class;
  // And make this class extendable
  Class.extend = arguments.callee;
   
  return Class;
 };
})();

Among them, "initializing/don't call init" and "creating _super method" are the most difficult. Next, I will give a brief introduction to this so that everyone can better understand its implementation mechanism.

Initialization

In order to illustrate the function prototype inheritance method, let’s first look at the traditional implementation process, which is to point the prototype attribute of the subclass to an instance of the parent class. As shown below:


function Person ( ) { }
function Ninja ( ) { }
Ninja. prototype = new Person ( );
// Allows for instanceof to work:
(new Ninja()) instanceof Person

However, the challenging point here is that we only want to get the effect of ‘instatnceOf’, without the consequences of instantiating a Person and calling its constructor. To prevent this, set a bool parameter initializing in the code, whose value will be true only when the parent class is instantiated and configured to the prototype property of the child class. The purpose of this processing is to distinguish the difference between calling the constructor during real instantiation and design inheritance, and then call the init method during real instantiation:

if ( !initializing )
 this.init.apply(this, arguments);

It is worth paying special attention to because in the init function, quite resource-intensive code may be run (such as connecting to the server, creating DOM elements, etc., no one can predict), so it is completely necessary to make a distinction.

Super Method

When using inheritance, the most common requirement is that the subclass can access the overridden methods of the superclass. In this implementation, the final solution is to provide a temporary method (._super) that points to the superclass method and can only be accessed in the subclass method.

var Person = Class. extend ( {
 init: function (isDancing ) {
  this. dancing = isDancing;
 }
} );
var Ninja = Person.extend({
 init: function(){
  this._super( false );
 }
});
var p = new Person(true);
p.dancing; // => true
var n = new Ninja();
n.dancing; // => false


Implementing this functionality requires several steps. First, we use extend to merge the basic Person instance (class instance, whose construction process we mentioned above) with the literal object (function parameter of Person.extend()). During the merging process, a simple check was made: first check whether the attribute to be merged is a function, if so, then check whether the superclass attribute to be overwritten is also a function? If both checks are true, you need to prepare a _super method for this property.

Note that an anonymous closure (returning a function object) is created here to encapsulate the added super method. Based on the need to maintain the running environment, we should save the old this._super (whether it exists or not) to be reset after the function is run. This helps in cases where there is the same name (don't want to accidentally lose the object pointer) Unpredictable problems.

Then, create a new _super method that points only to the overridden method in the super class. Thank God, there is no need to make any changes to _super or change the scope, because the execution environment of the function will automatically change with the function calling object (the pointer this will point to the super class).

Finally, call the method of the literal object. This._super() may be used during method execution. After the method is executed, the attribute _super is reset to its original state, and then return exits the function.


There are many ways to achieve the same effect (I have seen binding super to itself before and then accessing it with arguments.callee), but I feel that this method best reflects the characteristics of usability and simplicity.

Among the many works based on JavaScript prototypes that I have completed, this is the only class inheritance implementation plan that I have published to share with you. I think that concise code (easy to learn, easy to inherit, less downloading) needs to be put forward for everyone to discuss. Therefore, for people who learn JavaScript class construction and inheritance, this implementation plan is a good start.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn