/* Based on Alex Arnell's inheritance implementation. */
var Class = (function() {
//Temporarily store the parent's prototype
function subclass() {} ;
//Method to create a class
function create() {
var parent = null, properties = $A(arguments);
//Check whether to specify when creating a new class A parent object
//If a parent class is specified, assign the value to parent
if (Object.isFunction(properties[0]))
parent = properties.shift();
//The class actually used to return, 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 for class-level method expansion
Object.extend(klass, Class.Methods);
// Add two attributes to the returned class, superclass: parent class, subclasses: collection of subclasses
klass.superclass = parent;
klass.subclasses = [];
//If you create a class When the parent object is specified, point the prototype of klass to the instance of the parent object to implement prototype chain inheritance
if (parent) {
subclass.prototype = parent.prototype;
klass.prototype = new subclass;
//Add subclasses to the parent class and maintain the subclass collection of the parent class
parent.subclasses.push(klass);
}
//Add methods 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 will be used by default Assign to the initialization method
if (!klass.prototype.initialize)
klass.prototype.initialize = Prototype.emptyFunction;
/*
* Correct the constructor of the new class so that the constructor The function points to itself, here is a special mention (if you comment out the following line):
* 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? Man's constructor actually points to Person's constructor
* The root of the problem lies in the sentence klass.prototype = new subclass;
* I will not explain the specific reason. For a detailed understanding, please see "JavaScript Language" Essence and Programming Practice" pages 155~160
*/
klass.prototype.constructor = klass;
return klass;
}
//Add the method when creating the class to a new class, or add a class-level method after creating the class
function addMethods(source) {
//Get 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 it is written like this. If you know, tell me?
if (!Object .keys({ toString: true }).length) {
//If the new class overrides the toString and valueOf methods, add them
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, value is the function body
var property = properties[i], value = source[property];
//Determine whether this method needs to call the method of the same name of the parent class
if (ancestor && Object.isFunction(value) &&
value.argumentNames ().first() == "$super") {
var method = value;
//This is very important!
//Replace the $super parameter so that this parameter points to the method of the same name of the parent class
//The wrap method of Function is used here. For the explanation of the wrap method, please refer to [Prototype Learning - Function Object]
/ /Method is a new definition method, so his first parameter is $ super, and then returns from '=' to '.' to return the method of the same name
// Replace the parameters with the method of the same name of the parent class, so that when the subclass calls $super(), the method of the same name of the parent class will be called
//The construction here is great!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
🎜>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 2 methods: create and addMethods, which are clearly explained in the source code comments above. Let’s look at some examples to explain the usage in detail:
//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
//Note the usage of $super here, check the explanation in the source code Take a closer look
say: function($super, message) {
return $super(message) ', yarr!';
}
});
var john = new Pirate('Long John');
john.say('ahoy matey');
// -> "Long John: ahoy matey, yarr!"
var john = new Pirate('Long John');
john.sleep();
// -> ERROR: sleep is not a method
// every person should be able to sleep, not just pirates!
//This is The usage of addMethods can be extended at the class level.
Person.addMethods({
sleep: function() {
return this.say('ZzZ');
}
});
john.sleep();
//Here are the usage of the two attributes superclass and subclasses
Person.superclass
// -> null
Person.subclasses.length
// - > 1
Person.subclasses.first() == Pirate
// -> true
Pirate.superclass == Person
// -> true
The three examples cover the methods of the Class class. For detailed examples, please refer to: http://prototypejs.org/learn/class-inheritance