The topic is a little Big-.-。
Haven't written a blog for a long time, this period suddenly can't find the topic. Recently I have just reconstructed the front-end form of the function, through the reference, and take advantage of the object-oriented approach, there is a little bit of code, so take it out to share.
JavaScript Object-oriented way, I also learned through the blog garden, if you are not very clear, you can first look at the JavaScript function,function.prototype.
Before writing, a key idea was identified, and the test was written first. For the sake of simplicity, a simple unit test function was written, and then some functions, such as namespaces, classes, and inheritance of classes, were first implemented.
Unit Test function
Mainly includes a test method:
Test (method to be tested, results tested)
Test (method to be tested, method of testing results)
Cases:
function Getsum (A, b) {
return a + B;
}
Test ("Getsum", getsum) = = 3);
Test ("Getsum", function (msgwrite) {
Msgwrite ("1+2=?");
return getsum = = 3
});
Implementation is very simple, first put on the code, you crossing interested in their own look.
(function(window, body) {varTRP = window.document.createElement ("div"); if(body) {body.appendchild (TRP); } Else{Window.addeventlistener ("Load",function() {window.document.body.appendChild (TRP); }); } functionWriteresult (Panel, msg) {varresult = Window.document.createElement ("div"); Result.innerhtml=encodehtml (msg); Panel.appendchild (result); } window.test=function(item, ARG) {varItempanel = window.document.createElement ("div"); Itempanel.innerhtml= "<p>" + encodehtml (item) + "</p>"; Trp.appendchild (Itempanel); varMsgpanel = window.document.createElement ("div"); Itempanel.appendchild (Msgpanel); if(typeof(arg) = = "Boolean") { } Else if(typeof(arg) = = "function") { Try{arg= ARG (function(msg) {Writeresult (Msgpanel, msg); }); } Catch(e) {arg=false; Writeresult (Msgpanel, E); }} writeresult (Msgpanel, Arg? "Success": "Failed"); if(ARG) {itempanel.style["Background"] = "#0f0"; } Else{itempanel.style["Background"] = "#f00"; } };}) (window, window.document.body);
Testcore.js
Introduce the testcore.js and the function implementation JS and the unit test JS into an HTML, and open the HTML to see the unit test results. Red for failure, green for success.
namespace, class, Class-Inherited unit tests
Writing unit tests, in fact, represents the needs of our time. The following is the demand of this time.
Name space
The ability to register namespaces allows classes to be added under the space, and classes with the same name can be registered under each space.
Test ("Frame registration",!! WOD &&!! WoD. CLS);
WoD the namespace of the core library itself
The CLS is the base class for all current classes and is equivalent to. NET object.
Test ("Register namespace",!!) WoD. Cls.getns ("Mini.ui") &&!! Mini.ui && WOD. Cls.getns ("mini.ui") = = Mini.ui);
Classes, inheritance of classes
CLS also provides a core approach
Getns ("namespace"), if no namespace exists, registers and returns the Namespace object, if present, returns the object
Because of the MINIUI on the recent project, Mini.ui is lying on the gun.
Test ("Registration Class",!! WoD. Cls.getclass ("Mini.ui.TextBox") &&!!Mini.ui.TextBox); Mini.ui.TextBox.prototype.getText=function () { return"ABC"; }; Test ("Inherit class",!! WoD. Cls.getclass ("Mini.ui.SubTextBox", "Mini.ui.TextBox") &&!!Mini.ui.SubTextBox
&&!! New Mini.ui.SubTextBox ()&&mini.ui.SubTextBox.isSubclassOf (Mini.ui.TextBox)); Test (Inherit class-Inheritance method validation 1,function(msgwrite) {varSub =NewMini.ui.SubTextBox (); returnSub.gettext && sub.gettext () = = "ABC"; }); Test (Inherit class-Inheritance method Validation 2,function(msgwrite) {varSubcls =WOD. Cls.getclass ({getText:function () { return"H" + This. Parent (); }, HH:function () { return This. GetText (); } }, "Mini.ui.SubTextBox1", "Mini.ui.SubTextBox"); varSub =Newsubcls (); returnSub.gettext && sub.gettext () = = "Habc" &&sub.hh; });
Overloaded with four GetClass methods:
1, GetClass (className), register a ClassName class (default inheritance CLS), and then add properties and methods to the class by prototype
2. GetClass (attr,classname), register a ClassName class (default inheritance CLS), append attr properties and methods to the ClassName class
3, GetClass (classname,baseclassname), register a ClassName class, inherit from Baseclassname, and then add properties and methods to the class by prototype
4, GetClass (attr,classname,baseclassname), register a ClassName class, inherit from Baseclassname, add attr properties and methods to ClassName class
The above unit tests illustrate the need for this implementation:
1, can register the class, this class must register successfully
2, the registered class, can be instantiated directly through the new keyword, through the property can set its properties and methods
3, the registered class contains the IsSubclassOf method to determine the subclass of a class
4, the subclass of the same name method will override the base class method, and within the method, through This.parent (ARG) to call the base class of this method (from Impactjs, it is very useful to implement similar c#base. function of Method ()
Implementation of core libraries
After the test was finished, we finally started to play the =.=.
For JavaScript, there is no namespace, and all he has is the object. In order for him to support namespaces, you can use objects to represent namespaces, and if that space includes subspace, then increase the properties of the subspace on that object, as in the following
var System = new Object ();
System.window = new Object ();
So the namespace of our core library is implemented like this.
var New Object ();
=.= is so shabby.
Then there is the class, so our WOD. CLS cannot be an object, he must be a function
function (){};
Why so humble and =.=.
In WOD. The addition of the Getns (namespace) method on the CLS makes it easy to implement it by means of the new Object ():
WoD. Cls.getns =function(nsname) {vararr; if(!nsname | | (arr = Nsname.split (".")) && Arr.length = = 0)) returnundefined; varBase =window; for(vari = 0, length = arr.length; i < length; i++) { if(Base[arr[i]]) {}Else{Base[arr[i]]=NewObject (); } Base=Base[arr[i]]; } returnBase; };
Then to implement the registration class:
WoD. Cls.getclass =function(classname,baseclassname) {varBaseClass = eval ("(" +baseclassname+ ")");//here Baseclassname must be present, and the function of the base class is obtained . varconstruct =function(){ };//Initializes a current classConstruct._super = BaseClass;//record his basic is BaseClass varNS = This. Getclassns (ClassName);//get NS via classnameNs[classname.splite ('. '). Pop ()] = construct;//placing the class on the NS returnconstruct;};
This is a basic prototype.
The following need to improve the alignment to achieve issubclassof, inheritance, parent and other functions.
Since our class is implemented by function, we can increase the method
Function.prototype.isSubclassOf = function if (this . _super = = null ) return false ; if (this . _super === base) return true ; else { return this ._super.issubclassof (base ); } };
Then inheritance, we can create an instance of BaseClass and put all the properties of that instance on the prototype of the current class, and then all new instances of the current class will naturally have all the methods of BaseClass.
new BaseClass ();
again is the construction method, we often need to define a method of constructing a class, such as the new Person (personname) Form. However, the instance method of our registered class cannot be defined freely, so there is a workaround. My method is to add a _init method, by the _init method of each subclass to implement its own construction method, so construct becomes this:
var function () { this. _init.apply (This, arguments); No matter how many parameters are in the constructor, they are transmitted to the _init method in a non-leaking way }
We also use the parent to implement similar c#base. Method (), so each class has the parent approach, so add the method to the CLS and search for the corresponding base class method by Construct._super, and call him:
WoD. CLS =function () { This. Parent =function () { varCLS = This. Constructor; varCaller =Arguments.callee.caller; varfinded =false; varresult; while(!finded) { for(varTmpinchcls.prototype) {if(Cls.prototype[tmp] = =caller) { if(Cls._superpt[tmp] && cls._superpt[tmp]! =caller) {Result= Cls._superpt[tmp].apply ( This, arguments); finded=true; } Break; } } if(!finded) {CLS=Cls._super; } } returnresult; }; };
The merit is almost gaocheng.
Now, we can define our class arbitrarily,
Let's write an example:
WOD. Cls.getclass ({name:"", Eat:function(food) {alert ( This. name+ ' is eating ' + food + '! '); }},' My.eatbase '); WoD. Cls.getclass ({name:"Cat"},' My.cat '); WoD. Cls.getclass ({_init:function(name) { This. Name = name| | This. Name; This. Parent (name); }, Name:"Dog"},' My.dog ');NewMy.dog (). Eat ();NewMy.dog (' Wang Fu '). Eat ();NewMy.cat (). Eat ();
What about it?
So it's over. You can download it at the back of the link to play a bit.
In order to attribute the elegant attached to the prototype also use the Mixin and Clone method, you can get to know the clone mixin extend. I couldn't find the Web page I had seen before ... and found it and put it up again.
When adding object properties to prototype, when using the new keyword, multiple objects will share this object property in prototype, so the CLS _init method uses clone to set different values for different objects. This problem also caused a bug =.= in the project.
Download
JavaScript Object-oriented