1) Insufficient and improvement of JavaScript inheritance mechanism
Question (1) Since JavaScript is "pseudo inheritance" to take the prototype mechanism, prototype must display the reference "base class" object, so it is destined that JavaScript can only implement "weak inheritance", or "object inheritance" Note that the order of the order here needs Clearly, Prototype's assignment must be outside the object structure. E.g:
Function classa () {classa.prototype.methoda = function () {...}} function classb () {classb.prototype.methoda = function () {...}} classb.prototype = new classa (); / / Note Here the declaration B inherits from A to appear outside the function classb () function body, and the configuration of the // Classb object is executed. Since it is such a mechanism, there is two points to note: First, no persistence operations should be performed in the constructor of the class, such as the overall or DOM object construct, because if you do this, when using this When the class is inherited, even if you only instantiate an object, this class's constructor may also be executed more than once! (Conversely, in the language of the true face-to-object, such as C and Java, when we use Singleton mode, it is often allowed to perform a persistence operation in the constructor. If you are used to this mode, it is easy in JavaScript. !), For example: Function UNIQueform (URL) {this.id = 'myform'; this.action = url uniqueform.prototype.form_submit = function () {...} this.form = document.createElement ('form'); // The problem is here, persistent operation in the constructor ...} function uniquevalidateform (URL) {... .......} uniquevalidateform.ProtoType = new uniqueform () ;
Var myform = new uniquevalidateform ('test.aspx'); // This statement is actually constructed is the second FORM element, // The first element in inherited statement uniquevalidateform.Prototype = new uniqueform () // has been constructed.
A method of avoiding this problem is to use the factory: function formfactory () {formFactory.getCurrentform = function () {if (formfactory.form == null) {formfactory.form = document.createElement ('form');} return flmfactory; }} Two classes of Document.createElement ('form') in the above example; change to FormFactory.getCurrentForm ().
Question (2) Inheritance of class properties: The root of the problem is also the object inheritance mechanism of JavaScript. The inheritance implemented by Prototype is easy to obtain the object attributes and object methods of the base class, but it is not possible to obtain a class method for the base class. The true object-oriented inheritance should be inherited at the same time and the object method. A solution that can solve this problem is to use the method of reflecting the base class to be added to the subclass. E.g:
Function classa () {classa.prototype.methoda = function () {...} // This is an object method classa.methoda = function () {...} // This is a class method}
Function classb () {...} classb.prototype = new classa (); for (Each in classa) {classb [EACH] = function () {classa [EACH]}; // Put classa method Also inherited}
Var obj = new classb (); obj.methoda (); // calls the object method of inheriting from A classb.methoda (); // Call inherited from a class method
Question (3) Basic class construction with parameters: As mentioned above, due to the limitations of Prototype and object inheritance, the base class object must be instantiated before constructing a bobbin object, which gives us a very strong inheritance. Great trouble. One solution is to wait until the need to construct the object to deal with inheritance, for example: classb.prototype = new classa (1, 2); // Implement inheritance VAR OBJB = New Classb (1, 2) before the construction; Classb .prototype = new classa (-1, -2); // Another configuration, the parameters are different, so to override the inheritance var objc = new classb (-1, -2); of course, like the above practice gives people feel Very bad, it is not like inherited.
There is another approach to let B constructor does not rely on the constructor of A, that is, rewriting the constructor logic implemented in all A, but only inherits B attribute domain and method domain, so When the declaration is inherited, as long as the constructor provided to a is provided with any set of legal parameters. Of course, this method is also very troublesome.
In fact, to solve the above problem, you must consider reserving access to the A domain in B and abstract constructor logic. E.g:
Function ClassA (X, Y) {classa.prototype.constructor = function (x, y) {...} ... if (x! = null || y! = null) this.constructor (x, y);} Function classb (x, y) {classb.prototype.constructor = function (x, y) {this.base.constructor (x, y); // Call the constructor of the base class.. .... // Perform your own constructor} ... if (x! = Null || y! = Null) this.constructor (x, y);} classb.prototype = new classa () Classb.Prototype.base = new classa (); // with no ginseng inheritance
Var objb = new classb (1, 2); var objc = new classb (-1, -2);
2) Event driver mechanism and callback function Realize the flexibility of JavaScript makes it easy to implement event drivers and callbacks, and the only trouble is the this pointer. In general, in the object-oriented THIS pointer, the THIS pointer to the object is only referring to the object itself, and there should be no other meaning. In general, the THIS pointer can work well in the JavaScript object method, but it is a pity that it does not apply when faced with the incident. The root cause is because JavaScript's THIS pointer is changed as the caller. In a general object method, the caller is naturally the object itself, but in the callback function and event function, the caller may be the true commissator of an external object or event. For example: function classa () {this.button = document.createElement ('input'); this.Button.Type = 'Button'; ...... this.button.onclick = Classa. Prototype.button_click; this.text = 'Please click'; this.count = 0; ... ... ...... Classa.Prototype.Button_Click = Function () // Can't get the correct result {Alert ('Clicks: " Not a ClassA object}} In complex events and callbacks, it may contain mutual calls and event associations between member functions, and we certainly can't take a lot of energy to judge the THIS pointer, a smarter The solution is to introduce a fixed event registration mode, such as the code written above: function classa () {this.Button = Document.createElement ('Input'); this.Button.Type = 'Button'; .... .. ... this.button.eventhandler = this; this.button.onclick = function () {this.EventHandler.Button_Click (this, event);}; // Note that this function is actually On behalf of Button this.text = ', please click'; this.count = 0; ... ... ...... Classa.Prototype.Button_Click = Function (Sender, Event) {Alert ('Clicks: " this.count); / / correct This.Button.text = 'Please click'; // or sender.text is simpler}}
3) Abstract class Abstract class is an important element for object-oriented design. To play JavaScript-oriented polymorphism, you must find a mechanism for implementing an abstract class. JavaScript flexibility allows us to implement it in a simple manner, for example: function abstract {abscracta.prototype.a = function () {...} ... ....... ..... if (Implement! = True) {throw new error ('Abstract class Abstracta can not construct an instance!');}} Function classa ()}} classa.prototype = new Abstracta (True ); 4) Interface: The interface is also a very important element, but it is more complicated to achieve it: function interfacea (obja) {if (obja.methoda == obja.methoda) throw new error ('interfacea method Methoda is not implemented in the object! "); If (obja.methoda == obja.methoDB) throw new error ('interfacea method Methodb is not implemented in the object!"); ...... ..... Function classa () {...} classa.prototype = new interfacea (new classa ());
5) Advanced Reflection Technology - Metadata Management and Polymorphism Tune We use the JavaScript class to generate an object, how to quickly obtain this object's handle, reflecting technology provides us with a thinking, even we can still Dynamically get all the instances of a class family in the runtime environment without knowing their object names in advance. In addition, an important use of this technique is to achieve the persistence of local objects. Since this is a more complex application, you can only experience its convenience in some complex tasks, you can only give an extremely simple example:
Function classa (id) {this.id = ID; // This ID is important for the establishment of metadata is important classa.instances [id] = this; classa.instances.all.push (this); ...... ...} Classa.instances = new array (); classa.instances.all = new array ();
Var obja = new classa ('myobja');
Inside the outside classa.instances ['myobja'] can directly access Obja without knowing the object name Obja, and can also access all ClassA instances by traverse Classa.instances.all.