A simple and object-oriented basic javascript framework
If the company will allow me to build a new and complete system independently in the future, I will certainly write another front-end framework for this system. How should I write this framework? In my previous blog, I showed you a framework that I wrote myself. Due to the time constraints, I have never fully thought about how to write this framework before, so I have a lot of regrets about this framework afterwards, after I restructured the code once, I didn't do any reconstruction operations any more, because I didn't want to fix it any more. The reason why I had this idea, I am not satisfied with the infrastructure of the framework I wrote. Why are you not satisfied with this infrastructure? Let's take a look at how I encapsulated the framework: copy the code (function (window, document) {var o1 ={}, o2 ={}; var outerObj = {o1: o1, o2: o2} window. outerObj = outerObj;}) (window, document, undefined) copy the Code. This code is written by reference to jQuery. Now let's look back, this writing method is nothing more than using anonymous functions to protect internal code. In addition, it does not really use any other javascript language features. However, at that time, I still had my own considerations, mainly from the following three perspectives: to improve the website performance, We must minimize the number of requests during page loading, therefore, the fewer external javascript files, the better. The smaller the size of a single request, the smaller the javascript code on the page. Learn from jQuery, the code written on the page should have a fixed routine. As long as both pages use javascript code, they should be migrated to their own javascript libraries. Secondly, error-prone code in page javascript development should be completed by the javascript library. Therefore, when I develop a javascript library, I migrate a large amount of code to an external file, some of these codes are basic code, such as some tool classes, grid building code, and mask functions, and some code is Business Code such as encryption and decryption, these are all concentrated in an external file. Because the structure of the original framework only wraps the Code through anonymous functions, it does not decouple the basic code from the Business Code, therefore, j The avascript library is a hodgedge. Many things are intertwined, which makes it difficult to maintain code and often turns into hard coding. All in all, the infrastructure of my previous javascript library is not very scalable and scalable, and it does not have the ability to isolate different types of code, so I need a new basic javascript framework, in this way, I will develop a javascript library later. This infrastructure makes the library more robust. Recently I have implemented some front-end projects. In this project, a single page is very complex and has many functions. The javascript Business Code of a single page is several hundred lines, and thousands of lines are more, therefore, there is a large public library in our front-end application, but each page has to write an external javascript file for corresponding business processing, the following is the basic structure of javascript code writing for this project: copy the code var opts = {version: "1.0.0", name: "sharpxiajun"}; (function (opts) {function Clazz () {return this. init (arguments);} Clazz. fn = Clazz. prototype = {init: function (opts) {this. settings = opts; return this;}, testInit: function () {// directly print the object cons Ole. log (this. settings); // traverses the object output for (var o in this. settings) {console. log (this. settings [o]);} return this ;}} window. $ = new Clazz (opts)}) (opts); // test $. testInit (); copy the code and run the following results: whether we use an external public class library or a javascript external file corresponding to each page, we use this structure and carefully analyze the code, it is not clever with the structure of the previously written javascript library, except that my previous javascript library directly uses javascript objects, and this structure is nothing more than an object-oriented method, in fact, this object-oriented method is difficult to use inherited object-oriented methods and is an isolated object. Therefore, in actual development, we have to create multiple different functional objects to differentiate different functional modules, finally, there will be N or more Feature objects are independent of each other, which is not easy to expand as in my original library. In addition, this code makes me very uncomfortable during development, that is, in specific page development, I must first build a parameter object and upload the object to the interface of the external file, if you do not construct a parameter object in advance, an error occurs in the external javascript code. However, the difference between the two writing methods gave me a new idea for writing javascript libraries. The idea is as follows: in a web front-end application, exclude some public libraries, such as jQuery, which I must use, and libraries with time controls. (I will try to minimize the number of external libraries, such as jQuery and requireJs, when making web Front-end estimates, I basically use a library like seajs without reservation. I will try my best to discard a library like eaysui, jqgrid, and extjs.) Other javascript code should be compiled by programmers themselves, the code written by the programmer itself, whether it is business code or general Code, should be a whole. The overall performance is that they can all be output using an object, let's take a look at the basic structure of the two write libraries I mentioned above. Their common problems are that the common code and Business Code are intertwined, coupled, or independent of each other, and the relationship is stiff. In addition, it is very important to merge javascript into a small number of files in production. The writing method of the second library above (extract the Business Code of the page to external files) one of the purposes is to make file merging easier, but this stacked file merging always makes me feel a little uncomfortable. I think there are many advantages for a single javascript external file on a complex page. This practice cannot be abandoned, but it is best to have a logical relationship with a large public library, this relationship is most like the relationship between the original jQuery library and its plug-ins. If there is such a relationship, we will merge the files, and this will feel much better. Finally, I did not use object-oriented programming to write my own databases. I used the characteristics of javascript objects. If I switched to object-oriented programming, it would be a static variable scheme of classes, another write rule is the implementation scheme of instantiating objects. I think both write methods have advantages and disadvantages. It is better that the library we designed should be compatible with these two mechanisms. The following is the new basic javascript framework model I have written based on the above ideas. The Code is as follows: copy the code (function (window, document) {function Clazz () {return this. init (arguments);} Clazz. fn = Clazz. prototype = {init: function (opts) {this. settings = opts; return this;}, testInit: function () {// print the object console directly. log (this. settings); // traverses the object output for (var o in this. settings) {console. log (this. settings [o]);} return this ;}}; Clazz. addStaticMethod = function (nmSpac E, obj, ftn) {if (! Clazz [nmSpace]) {Clazz [nmSpace] ={}} for (var I in obj) {Clazz [nmSpace] [I] = obj [I];} if (ftn) {ftn ()} Clazz. addObjectMethod = function (nmSpace, obj, ftn) {if (! Clazz. fn [nmSpace]) {Clazz. fn [nmSpace] ={}}for (var I in obj) {Clazz. fn [nmSpace] [I] = obj [I];} if (ftn) {ftn ()} window. clazz = Clazz;}) (window, document, undefined) var opts = {version: "1.0.0", name: "sharpxiajun"}; Clazz. addStaticMethod ("myStatic", {sClz: "static", staticFtn: function () {console. log (Clazz ["myStatic"]. sClz) ;}, function () {console. log ("Add Static Method End !!!!!!! ");}) Clazz. addObjectMethod ("myFirst", {sParam: "sharp", ftn01: function (s) {this. sParam = s; return this;}, ftn02: function () {console. log ("sParam:" + this. sParam); return this ;}}, function () {console. log ("Add Object Method End !!!!!!! ") ;}) Var $ = new Clazz (opts); // test $. testInit (); // test the second console. log ($. myFirst. sParam); $. myFirst. ftn01 ("My God !!! "). Ftn02 (); // test console 3. log (Clazz. myStatic. sClz); Clazz. myStatic. staticFtn (); copy the code page and run the following results: in this code, I return a class in an anonymous function. (In javascript, there is actually no class concept, but there is a constructor, so the constructors in javascript assume the role of classes, so it is okay to mention the classes in javascript here), rather than the objects that have been instantiated. In this way, the returned items can have both static methods and attributes and object methods and attributes. There is a Clazz in this structure. addStaticMethod is used to add a static method to the defined class. I have designed three parameters for this method. The first parameter is a string, and the business function is the scope of the static method, check the following instance code: console. log (Clazz. myStatic. sClz); Clazz. myStatic. staticFtn (); this is equivalent to providing protection for static variables. Someone will ask what if we do not pass the first parameter? Seriously, the code I have provided is just to express my thoughts. This method will be more plump when it comes to production implementation. At that time, if the user does not transmit the scope field, the added static methods and attributes directly belong to the class itself. The second parameter is the static attributes and static methods to be added. Here I use the object type. The third parameter is a callback function. It is called after the static method is successfully added. Of course, you can add a callback function parameter without passing the parameter, I think a callback function should be provided when designing javascript methods. This is the idea of using event-driven programming, which leaves room for myself, this often plays an important role in unexpected times. The method Clazz. addObjectMethod adds methods and attributes to the object. These methods and attribute stone are assigned to the prototype object. The parameter type is the same as addStaticMethod, which is not described here. When using the addObjectMethod method, you should pay attention to the use of this pointer. Add a return this to the end of each method to be added to the object, so that the return value of each object is the object itself, in this way, we can make our library have the same concatenation method as jQuery, such as the following code: console. log ($. myFirst. sParam); $. myFirst. ftn01 ("My God !!! "). Ftn02 (); in production and development, we can directly Write Public javascript code to the library, the Business Code on the page is directly expanded by extending the static methods and attributes of the returned class, as well as the object methods and attributes. The above structure basically meets my needs. If I use javascriptMVC idea to develop the front-end, I guess this basic structure is enough. Of course, I need to do some code robustness processing, if it is a traditional front-end page development, it is estimated that some modifications will be made. The page development of traditional websites is a mix of server and html, such as jsp and velocity files, therefore, many important data is generated by server variables. We often need to pass these variables as parameters to external javascript files. The parameters on each page are different, therefore, an object must receive this object. This is easy to do, so I will not go over it here. The above structure uses the Object-oriented Inheritance Mechanism. The original library is the parent object, while the business javascript file is a subclass. However, this subclass is distinguished by namespaces. However, sometimes we may want to take the risk of replacing the content of the entire parent object. This requirement is not common in normal development, but I still wrote this method, the following is my improved Code, specifically: copy the code (function (window, document) {function Clazz () {return this. _ init (arguments);} Clazz. prototype = {_ init: function (opts) {this. settings = opts; return this;}, testInit: function () {// print the object console directly. log (this. settings); // traverses the object output for (var o in this. settings) {console. log (this. settings [o]);} return this ;}}; Clazz. addStaticMe Thod = function (nmSpace, obj, ftn) {if (! Clazz [nmSpace]) {Clazz [nmSpace] ={}} if (Object. prototype. toString. apply (obj) = "[object Object]") {for (var I in obj) {Clazz [nmSpace] [I] = obj [I];} window. clazz = Clazz;} if (ftn) {ftn ()} Clazz. addObjectMethod = function (nmSpace, obj, ftn) {if (! Clazz. prototype [nmSpace]) {Clazz. prototype [nmSpace] ={}} if (Object. prototype. toString. apply (obj) = "[object Object]") {for (var I in obj) {Clazz. prototype [nmSpace] [I] = obj [I];} window. clazz = Clazz;} if (ftn) {ftn ()}/* Clazz. newStaticMethod () {// todo ..........} */Clazz. newObjectMethod = function (obj, ftn) {if (Object. prototype. toString. apply (obj) = "[object Object]") {var tmpInit = Clazz. prot Otype. _ init; Clazz. prototype = obj; Clazz. prototype. _ init = tmpInit; window. clazz = Clazz;} if (ftn) {ftn ()} window. clazz = Clazz;}) (window, document, undefined) var opts = {version: "1.0.0", name: "sharpxiajun"}; Clazz. addStaticMethod ("myStatic", {sClz: "static", staticFtn: function () {console. log (Clazz ["myStatic"]. sClz) ;}, function () {console. log ("Add Static Method End !!!!!!! ");}) Clazz. myStatic. staticFtn (); Clazz. newObjectMethod ({newver: "1.0.3", testNewFtn: function () {console. log (this. newver); return this ;}}, function () {console. log ("New Create Prototype Object End !!!!!! ") ;}); Clazz. addObjectMethod ("myFirst", {sParam: "sharp", ftn01: function (s) {this. sParam = s; return this;}, ftn02: function () {console. log ("sParam:" + this. sParam); return this ;}}, function () {console. log ("Add Object Method End !!!!!!! ") ;}) Var $ = new Clazz (); console. log ("================================"); console. log ($. newver); $. testNewFtn (). myFirst. ftn01 ("XXXX "). ftn02 (); console. log ("================================ "); the running result of the copied code is as follows: the code above has been optimized. In the code, I only provided a method to replace the prototype, but did not provide a static method to replace it, this is because replacing the prototype still makes some sense. Replacing static variables is actually replacing the entire class. If so, what is the significance of my structure.