Previous words
This article will introduce several key points of JS programming style in detail
Loose coupling
Loosely coupled when you modify a component without needing to change other components
1. Draw js out of CSS: do not use CSS expressions
Bad practice. Box{width:expression (document.body.offsetWidth + ' px ')}
2, draw the CSS from JS: When you modify CSS style by JS, use classname or classlist, do not modify style style
Bad practice one ele.style.color = ' red '; ele.style.left= ' 10px ';//bad practice two ele.style.cssText = ' color:red;left:10px; ';
. reveal{color:red;left:10px;} Good practice one ele.classname + = ' reveal ';//Good Practice two ele.classList.add (' reveal ');
3, the JS from the HTML extraction: from the JS file into the external file
4. Remove HTML from JS: Instead of stitching the DOM structure in innerHTML, use a string template, such as Handlerbars
Global variables
Creating global variables is considered bad practice, especially in the context of team development, which is a lot more problematic. As the amount of code grows, global variables lead to some very important maintainability challenges, the more global variables, the higher the probability of introducing errors
Generally speaking, there are three solutions
1, 0 global variables
The implementation method is to use an immediate call to the function Iife and place all the scripts in it
(function () { var doc = win.document;}) (window);
The use of this pattern is limited, as long as the code needs to be relied upon by other code, or it needs to be continuously extended or modified in the run, it cannot be used this way
2. Single Global variables and namespaces
Rely on as few global variables as possible, i.e. create only one global variable, using a single-variable pattern, such as Yui or jquery
Single global variable, which is the unique global object name created, is unique, and all function code is attached to this global object. Therefore, each possible global variable becomes a property of a unique global variable, so that multiple global variables are not created
A namespace is a simple functional grouping represented by a single property of a global object. For example, all methods under Y.dom are related to DOM operations, and all methods under Y.event are related to events. A common convention is that each file declares its own namespace through a new global object
3. Using the module
A module is a generic feature fragment that does not create a new global variable or namespace. Instead, all of this code is stored in a single function that represents executing a task or publishing an interface. This module can be represented by a name, and the same module can depend on other modules
Event handling
Coupling event-handling-related code and event environments, resulting in poor maintainability
1. Isolate application logic
Extracting application logic from all event handlers is a best practice to split code that applies logic and event handling
Bad practice function Handleclick (event) { var popup = document.getElementById (' popup '); Popup.style.left = event.clientx + ' px '; Popup.style.top = event.clienty + ' px '; Popup.classname = ' reveal ';} AddListener (element, ' click ', Handleclick);//Good practice var MyApplication = { Handleclick:function (event) { This.showpopup (event); }, showpopup:function (event) { var popup = document.getElementById (' popup '); Popup.style.left = event.clientx + ' px '; Popup.style.top = event.clienty + ' px '; Popup.classname = ' reveal '; }}; AddListener (element, ' click ', Function (event) { Myapplication.handleclick (event);});
2. Do not distribute event objects
The application logic should not rely on the event object to properly complete the function, and the method interface should indicate which data is necessary. A bug can result if the code is not clear. The best way to do this is to have the event handler use the event object to handle events, and then get all the required data to the application logic
Improved practice var MyApplication = { Handleclick:function (event) { this.showpopup (event.clientx,event.clienty); } , showpopup:function (x, y) { var popup = document.getElementById (' popup '); Popup.style.left = x + ' px '; Popup.style.top = y + ' px '; Popup.classname = ' reveal '; }}; AddListener (element, ' click ', Function (event) { Myapplication.handleclick (event);});
When handling events, it is a good idea to make the event program the only function that touches the event object. Event handlers should perform any necessary actions on the event object before entering the application logic, including blocking event bubbling, which should be included directly in the event handler
Improved practice var MyApplication = { Handleclick:function (event) { event.preventdefault (); Event.stoppropagation (); This.showpopup (Event.clientx,event.clienty); }, showpopup:function (x, y) { var popup = document.getElementById (' popup '); Popup.style.left = x + ' px '; Popup.style.top = y + ' px '; Popup.classname = ' reveal '; }}; AddListener (element, ' click ', Function (event) { Myapplication.handleclick (event);});
Configuration data
The code is nothing more than defining a collection of instructions for the computer to execute. We often pass data on to the computer, which operates on the data and ultimately produces a result. When you have to modify the data, you may introduce unnecessary risks. The key data should be drawn out of the code
Configuration data is a value that guides the death of the application and may be modified in the future, including the following
1, URL2, need to show to the user string 3, duplicate value 4, configuration item 5, any value that may change
The following is the practice of unhandled configuration data
Bad practice function Validate (value) { if (!value) { alert (' Invalid value '); Location.href= "/errors/invalid.php"; }} function toggleselected (Element) { if (hasclass (element, ' selected ')) { removeclass (element, ' selected '); } else{ addclass (element, ' selected ');} }
The following code saves the configuration data in the Config object, and each property of the Config object holds a fragment of data, each of which is prefixed to indicate the type of data (msg represents the information presented to the user, the URL represents the network address, and the CSS indicates that this is a classname )。 Of course, you can also place the entire config object in a separate file so that modifications to the configuration data can be completely isolated from the code that uses the data
Good practice var config = { msg_invalid_value: ' INVALID VALUE ', url_invalid: '/errors/invalid.php ', css_ SELECTED: ' SELECTED '}function Validate (value) { if (!value) { alert (config. Msg_invalid_value); Location.href=config. Url_invalid;} } function toggleselected (Element) { if (hasclass (element,config). css_selected)) { removeclass (element,config. css_selected); } else{ addclass (element,config. css_selected);} }
Selector optimization
Sets the element selected by the selector as the static property of the object into one place unified management
Initializeelements:function () { var eles = app. Eles; for (var name in eles) { if (Eles.hasownproperty (name)) { This[name] = $ (eles[name]); } }}
Here is an example
Good practice.
App. Eles = { widgetdiv: ". Left-widget div", inputresize: '. Input-resize ', hr: '. HR ', txt: '. Input-group-btn button ', cus: ' #paper-type-cus ', hid: ' #hidden ', maincon: ' #mainCon ', Rulerx: ' . Ruler-x ', rulery: '. ruler-y ',};
function optimization
"Refinement Function"
Most of the time in JavaScript development is working with functions, so hopefully these functions are well named, and the logic contained within the function is clear. If a function is too long and you have to add a few comments to make the function readable, then these functions are necessary to refactor
If there is a piece of code in the function that can be isolated, it is better to put the code into another separate function. This is a very common optimization work, the benefits of which are mainly the following points
1. Avoid super-large functions
2. Independent functions help with code reuse
3, independent function easier to overwrite
4, independent function if you have a good name, it acts as a comment.
For example, in a function to obtain user information, you also need to print the log associated with the user information, then the print log statement can be encapsulated in a separate function:
var GetUserInfo = function () { ajax ('//xxx.com/userinfo ', function (data) { console.log (' UserId: ' + Data.userid); Console.log (' userName: ' + data.username); Console.log (' nickname: ' + data.nickname); };/ /change to: var GetUserInfo = function () {Ajax (' http://xxx.com/userinfo ', function (data) {printdetails (data);}); };var printdetails = function (data) {Console.log (' userId: ' + Data.userid); Console.log (' userName: ' + Data.username); Console.log (' nickname: ' + data.nickname);};
"Minimize the number of parameters"
If you need to pass in more than one parameter when calling a function, the function is daunting and you have to figure out what these parameters mean, and you have to carefully pass them in in order. In practical development, it is unavoidable to pass parameters to the function, but the number of parameters received by the function should be minimized. Here's a very simple example. There is a drawing function draw, which now draws only squares and receives 3 parameters, the width of the graph, the Heigth, and square:
var draw = function (Width,height,square) {};
But actually the square area can be calculated by width and height, so we can remove the parameter square from the draw function:
var draw = function (width, height) { var square = width * height;};
Assuming that this draw function will begin to support the drawing of a circle, the parameter width and height must be replaced by radius radius, but the area square of the graph should never be passed on by the customer, but should be calculated from the inside of the draw function, with a certain rule in the parameters passed in. At this point, you can use the policy mode to make the draw function a function that supports drawing multiple graphs
"Passing object parameters instead of too long parameter list"
Sometimes a function can receive more than one parameter, and the more the number of arguments, the more difficult it is to understand and use. The person who uses the function first has to understand the meaning of all the parameters, in the use of the time, but also to be cautious, so as not to pass a parameter or two parameters to reverse the position. If you want to add a new parameter to the 3rd and 4th parameters, it involves a lot of code changes, the code is as follows:
var setuserinfo = function (ID, name, address, sex, mobile, QQ) { console.log (' id= ' + ID); Console.log (' name= ' +name); Console.log (' address= ' + address); Console.log (' sex= ' + sex); Console.log (' mobile= ' + mobile); Console.log (' qq= ' + QQ);}; Setuserinfo (1314, ' Xiaohuochai ', ' Beijing ', ' Male ', ' 150******** ', 121631835);
At this point you can put the parameters into an object, and then pass the object into the Setuserinfo function, the Setuserinfo function needs data can be obtained from the object itself. Now no longer care about the number and order of parameters, as long as the parameter corresponding to the key value of the same can be:
var setuserinfo = function (obj) { console.log (' id= ' + obj.id); Console.log (' name= ' + obj.name); Console.log (' address= ' + obj.address); Console.log (' sex= ' + obj.sex); Console.log (' mobile= ' + obj.mobile); Console.log (' qq= ' + obj.qq);}; Setuserinfo ({id:1314, Name: ' X Iaohuochai ', Address: ' Beijing ', Sex: ' Male ', Mobile: ' 150******** ', qq:121631835 });
Condition optimization
"Merge Conditional Fragments"
If there are conditional branching statements in a function body, and these conditional branching statements internally scatter some duplicated code, then it is necessary to merge and redo the work. If there is a paging function paging, the function receives a parameter currpage,currpage represents the page number that will jump. Before jumping, to prevent currpage from passing too small or too large numbers, to manually modify its value, see the following pseudo-code:
var paging = function (currpage) { if (currpage <= 0 ) { currpage = 0; Jump (Currpage); Jump }else if (currpage >= totalpage) { currpage = totalpage; Jump (Currpage); Jump }else{jumps (currpage);//Jump }};
As you can see, the code jump (Currpage) that is responsible for jumping appears within each of the conditional branches, so it is entirely possible to separate the code:
var paging = function (currpage) { if (currpage <= 0 ) { currpage = 0; } else if (currpage >= totalpage) { currpage = totalpage; } Jump (Currpage); Separate the jump function out};
"Refining conditional branching statements into functions"
In the program design, the complex conditional branching statements are the important reason that the program is difficult to read and understand, and it is easy to lead to a large function. Suppose there is a need to write a getprice function that calculates the price of a commodity, the calculation of a commodity has only one rule: if it is currently in the summer, then all the goods will be sold at 80 percent. The code is as follows:
var GetPrice = Function (price) { var date = new date (); if (Date.getmonth () >= 6 && date.getmonth () <= 9) {//Summer return price * 0.8; } return price ;};
Observe this code:
Date.getmonth () >=6&&date.getmonth () <=9
The meaning of this code is simple to judge whether it is currently in the summer (July-October). Although the code is short, the intent of the code expression is still some distance from the code itself, and the person reading the code must devote a little more effort to understand the intentions it conveys. In fact, this code can be refined into a single function, not only to more accurately express the meaning of the code, function name itself can play the role of annotations. The code is as follows:
var Issummer = function () { var date = new date (); Return Date.getmonth () >= 6 && date.getmonth () <= 9;}; var GetPrice = Function (price) { if (Issummer ()) {//Summer return price * 0.8; } return price ;};
"Let function exit in advance instead of nested conditional branches"
Many programmers have the idea that "each function can have only one entry and one exit." "Modern programming languages restrict functions to only one entry. But there are a few different opinions about "function has only one exit". The following pseudo code is a typical code that follows the "function has only one exit":
var del = function (obj) { var ret; if (!obj.isreadonly) {///is not read-only to be deleted if (Obj.isfolder) {///If it is a folder ret = deletefolder (obj); } else if (obj.isfile) {//If the file is ret = deletefile (obj); } } return ret;};
Nested conditional branching statements are definitely a nightmare for code maintainers, and for people reading code, nested IF, else statements are more difficult to read and understand than tiled if and else. Nested conditional branches are often written by programmers who are convinced that "each function can have only one exit". In fact, if you are not interested in the remainder of the function, you should exit immediately. Directing the reader to see some unused else fragments will only hinder their understanding of the program.
You can then select some conditional branches and immediately let the function exit after entering these conditional branches. To do this, there is a common technique, which is to reverse the outer if expression when facing a nested if branch. The following is a reconstructed del function:
var del = function (obj) { if (obj.isreadonly) {//Invert if expression return; } If (obj.isfolder) { return deletefolder (obj); } If (obj.isfile) { return deletefile (obj);}};
Cycle optimization
"Proper use of circulation"
In the function body, if some code is actually responsible for some repetitive work, then the rational use of loops can not only accomplish the same function, but also can make the code less. Here is the code to create the Xhr object, in order to simplify the example, only consider the IE browser under version 9, the code is as follows:
var createxhr = function () { var xhr; Try{ xhr = new ActiveXObject (' msxml2.xmlhttp.6.0 ' ); } Catch(e) { try{xhr = new ActiveXObject (' msxml2.xmlhttp.3.0 ' );} Catch(e) {xhr = new ActiveXObject (' msxml2.xmlhttp ' );}} return xhr;}; var xhr = createxhr ();
Following the flexible use of loops, you can get the same effect as the above code:
Here we have the flexibility to use the loop, you can get the same effect as the above code: var createxhr = function () { var versions= [' msxml2.xmlhttp.6.0ddd ', ' msxml2.xmlhttp.3.0 ', ' msxml2.xmlhttp ' ]; for (var i = 0, version; version = Versions[i++ ];) { try{ return new ActiveXObject (version); } Catch(e) {}}};var xhr = CREATEXHR ();
"Exit multiple loops with return"
Suppose there is a double loop in the function body, which needs to be judged in the inner loop, and exit the outer loop when a critical condition is reached. Most of the time, a control tag variable is introduced:
var func = function () { var flag = False; for (var i = 0; i <, i++ ) {for (var j = 0; J < Ten; J + + ) { if (i * j >30 ) { F lag = True; break,} if (flag = = = True ) {break;}}};
The second approach is to set the loop flag:
var func = function () { outerloop: for (var i = 0; i <, i++ ) { innerloop: for (var j = 0; j < 10; J + + ) { if (i * j >30 ) {break outerloop; } }};
These two approaches are undoubtedly dizzying, and it is easier to simply exit the entire method when you need to abort the loop:
var func = function () {for (var i = 0; i < i++ ) {for (var j = 0; J <; J + + ) {
if (i * j >30
) { return; }
}};
Of course, using the return direct exit method poses a problem if there are some code that will be executed after the loop. If you quit the entire method early, the code will not get the chance to be executed:
var func = function () {for (var i = 0; i <, i++ ) {for (var j = 0; J <; J + + ) { if ( I * J >30 ) { return;}} } Console.log (i); This code has no chance of being executed};
To solve this problem, you can put the code behind the loop back, and if the code is more, it should be refined into a separate function:
var print = function (i) { console.log (i);}; var func = function () {for (var i = 0; i < i++ ) {for (var j = 0; J <; J + + ) {
if (i * j >30
) { return print (i);}}};
Func ();
8 Tips for optimizing JavaScript code