/* Based on Alex Arnell's inheritance implementation. */
var Class = (function() {
//Temporarily store parent's prototype
function subclass() {};
// Method of creating class
function create() {
var parent = null, properties = $A(arguments);
//Check whether a parent object is specified when creating a new class
//If the parent class is specified, assign it to parent
if ((properties[0]))
parent = ();
//The class that is really used as the return is initialized when creating an instance, the initialize method will be called for initialization
function klass() {
(this, arguments);
}
//Add addMethods method to klass, after calling create method
//You can still call the addMethods method for class-level method expansion
(klass, );
//Add two properties to the returned class, superclass: parent class, subclasses: collection of subclasses
= parent;
= [];
//If the parent object is specified when creating the class, point the prototype of klass to the instance of the parent object to realize prototype chain inheritance
if (parent) {
= ;
= new subclass;
//Add a child class to maintain the child class collection of the parent class
(klass);
}
//Add method to new class
for (var i = 0; i < ; i++)
(properties[i]);
//If no initialization method is specified, an empty method is assigned to the initialization method by default
if (!)
= ;
/*
* Fix the constructor of the new class so that the constructor points to itself. Let me specifically talk about it here (if comment out the following line):
* var Person=();
* var p1=new Person();
* alert(==Person) //true
* var Man=(Person)
* var m1=new Man();
* alert(==Man) //false
* alert(==Person) //true
* alert(==) //true
*
* Have you seen the problem? Man's constructor actually points to Person's constructor
* The root of the problem lies in = new subclass; this sentence
* I won't explain the specific reason. For detailed understanding, please check the "Essence of JavaScript Language and Programming Practice" pages 155~160
*/
= klass;
return klass;
}
//Add the method when creating the class to a new class, or add class-level methods after creating the class
function addMethods(source) {
//Get the parent class of the new class
var ancestor = && ;
var properties = (source);
//It seems that the following judgment is always true. I don’t know why I wrote this, so I will tell me if I know it?
if (!({ toString: true }).length) {
//If the new class overrides the toString and valueOf methods, add it
if ( != )
("toString");
if ( != )
("valueOf");
}
//Transfer all new class declaration methods
for (var i = 0, length = ; i < length; i++) {
//property is the function name, value is the function body
var property = properties[i], value = source[property];
//Determine whether this method needs to call the parent class's method with the same name
if (ancestor && (value) &&
().first() == "$super") {
var method = value;
//This is very important!
//Replace the $super parameter so that this parameter points to the parent class's method of the same name
//The wrap method of Function is applied here. For the explanation of wrap method, please refer to [Prototype Learning - Function Object]
//Method is a newly defined method, so its first parameter is $super, and then the method of the parent class with the same name is returned from '=' to '.'
// Finally, the wrap method is called to replace the $super parameter with the parent class's same name method. In this way, when the subclass calls $super(), the parent class's same name method will be called.
//The structure here is very good! Worth thinking about
value = (function(m) {
return function() { return ancestor[m].apply(this, arguments); };
})(property).wrap(method);
//Point the valueOf and toString of the newly generated value (i.e., the modified subclass method) to the method of the same name of the atomic class
//This is a legacy problem after calling the wrap method
= (method);
= (method);
}
//Add method to new class
[property] = value;
}
return this;
}
//Return the callable method of Class
return {
create: create,
Methods: {
addMethods: addMethods
}
};
})();