Prototype 'sobjectforclass-basedOOP. The basis of prototypeOOP programming. The source code is described in detail.
The Code is as follows:
/* Based on Alex Arnell's inheritance implementation .*/
Var Class = (function (){
// Temporarily store the prototype of the parent
Function subclass (){};
// Create a class
Function create (){
Var parent = null, properties = $ A (arguments );
// Check whether a parent object is specified when a new class is created
// If the parent class is specified, assign the value to the parent
If (Object. isFunction (properties [0])
Parent = properties. shift ();
// Actually used as the returned class. When creating an instance, the initialize method will be called for initialization.
Function klass (){
This. initialize. apply (this, arguments );
}
// Add the addMethods method to klass after calling the create Method
// You can still call the addMethods method to expand the class-level method.
Object. extend (klass, Class. Methods );
// Add two attributes to the returned class: superclass: parent class, subclasses: collection of child classes
Klass. superclass = parent;
Klass. subclasses = [];
// If a parent object is specified during class creation, the klass prototype is directed to the instance of the parent object to implement prototype chain inheritance.
If (parent ){
Subclass. prototype = parent. prototype;
Klass. prototype = new subclass;
// Add a subclass for the parent class to maintain the subclass set of the parent class
Parent. subclasses. push (klass );
}
// Add a method to the new class
For (var I = 0; I <properties. length; I ++)
Klass. addMethods (properties [I]);
// If no initialization method is specified, an empty method is assigned to the initialization method by default.
If (! Klass. prototype. initialize)
Klass. prototype. initialize = Prototype. emptyFunction;
/*
* Modify the constructor of the new class so that the constructor points to itself. Here, I will make a special remark (if the following line is commented out ):
* Var Person = Class. create ();
* Var p1 = new Person ();
* Alert (p1.constructor = Person) // true
* Var Man = Class. create (Person)
* Var m1 = new Man ();
* Alert (m1.constrcutor = Man) // false
* Alert (m1.constrcutor = Person) // true
* Alert (m1.construcctor = p1.constrcutor) // true
*
* Do you see the problem? The Man constructor actually points to the Person constructor.
* The root cause of the problem is klass. prototype = new subclass;
* I will not explain the specific reasons. For more information, see JavaScript language essence and programming practices 155 ~ Page 1
*/
Klass. prototype. constructor = klass;
Return klass;
}
// Add the method used to create a class to the new class, or add a class-level method after the class is created.
Function addMethods (source ){
// Obtain the parent class of the new class
Var ancestor = this. superclass & this. superclass. prototype;
Var properties = Object. keys (source );
// It seems that the following judgment is always true. I don't know why I wrote it. Tell me what I know?
If (! Object. keys ({toString: true}). length ){
// If the toString and valueOf methods are rewritten for the new class, add
If (source. toString! = Object. prototype. toString)
Properties. push ("toString ");
If (source. valueOf! = Object. prototype. valueOf)
Properties. push ("valueOf ");
}
// Traverse all methods in the new class declaration
For (var I = 0, length = properties. length; I <length; I ++ ){
// Property is the function name and value is the function body
Var property = properties [I], value = source [property];
// Determine whether to call a method with the same name as the parent class
If (ancestor & Object. isFunction (value )&&
Value. argumentNames (). first () = "$ super "){
Var method = value;
// This is important!
// Replace the $ super parameter so that this parameter points to the method with the same name as the parent class
// The wrap method of Function is applied here. For details about the wrap method, refer to [Prototype Learning-Function object]
// Method is the newly defined method, so its first parameter is $ super, and the same name method of the parent class is returned from '=' '.'.
// Call the wrap method to replace the $ super parameter with the method of the same name as the parent class. In this way, when the subclass calls $ super (), the method of the same name of the parent class is called.
// The structure here is very good! Worth thinking
Value = (function (m ){
Return function () {return ancestor [m]. apply (this, arguments );};
}) (Property). wrap (method );
// Point the valueOf and toString of the new value (that is, the modified subclass method) to the same name method of the atomic class.
// Here is the legacy problem after the wrap method is called.
Value. valueOf = method. valueOf. bind (method );
Value. toString = method. toString. bind (method );
}
// Add the method to the new class
This. prototype [property] = value;
}
Return this;
}
// Return the callable method of Class
Return {
Create: create,
Methods :{
AddMethods: addMethods
}
};
})();
This class provides two methods: create and addMethods. The above source code comments have clearly been described. Here are some examples to illustrate the usage:
The Code is as follows:
// Declare the Person class and define the initialization method
Var Person = Class. create ({
Initialize: function (name ){
This. name = name;
},
Say: function (message ){
Return this. name + ':' + message;
}
});
// When subclassing, specify the class you want to inherit from
Var Pirate = Class. create (Person ,{
// Redefine the speak method
// Pay attention to the $ super usage here. Take a closer look at the explanations in the source code.
Say: function ($ super, message ){
Return $ super (message) + ', yarr! ';
}
});
Var john = new Pirate ('long john ');
John. say ('ahoy mate ');
//-> "Long John: ahoy matey, yarr! "
The Code is as follows:
Var john = new Pirate ('long john ');
John. sleep ();
//-> ERROR: sleep is not a method
// Every person shocould be able to sleep, not just pirates!
// Here is the addMethods usage, which can be expanded at the class level
Person. addMethods ({
Sleep: function (){
Return this. say ('zzz ');
}
});
John. sleep ();
The Code is as follows:
// Here is the usage of the superclass and subclasses attributes
Person. superclass
//-> Null
Person. subclasses. length
//-> 1
Person. subclasses. first () = Pirate
//-> True
Pirate. superclass = Person
//-> True
Three examples several cover the Class method, for detailed examples see: http://prototypejs.org/learn/class-inheritance