The excellent Stoyan Stefanov in his new book ("Javascript Patterns") introduces many techniques for writing high-quality code, such as avoiding global variables, using a single var keyword, circulating pre-stored lengths, and so on.
This article not only from the code itself to consider how to optimize the coding, but also from the design phase of the code to consider, including writing API documentation, colleagues review, using JSLint. These habits can help you write more high-quality, easier-to-understand, maintainable code (so your code will be proud of you for years).
Write maintainable code
Software bug fixes take a lot of effort. Especially after the code has been released, the cost of maintenance has increased over time. When you find a bug, you fix it right away, your code is warm, and you don't need to remember, because it's just written. But when you do other tasks and almost completely forget the code, it's time to:
- Re-learning and understanding problems
- Understand how the code solves the problem
Another problem is that in large or large companies, it is often the person who solves the bug that is not the person who created the bug, and not the person who found it. So reducing the time to understand the code is the most important question, whether it's written by yourself or by other members of the team, because we want to engage in something new and interesting, rather than maintain those old code. Anda Shangqiang Antique
Another common problem in development is that it is often more time to read code than to write code. Sometimes when you delve into a problem, you can spend a whole afternoon thinking about writing the code. This code works at the time, but as the development progresses, other things have changed so much that you need to re-examine the changes and write the code yourself. Like what:
- There are bugs that don't work.
- New features added
- The program needs to run in a new environment (e.g. a new browser)
- Problem with the code
- The code needs to be rewritten because it modifies the schema and even uses another language
For these reasons, perhaps you wrote the code in an afternoon, and it took a few weeks to read it later. So writing maintainable code is critical to the success of your software. The maintainable code includes:
- Readability
- Continuity
- Predictive
- Looks like it was written by a man.
- Have documentation
Minimizing global variables
JavaScript uses functions to contract scopes. A variable declared inside a function is not visible externally. Therefore, a global variable is a variable declared outside of any function or not declared.
In JavaScript, there is an accessible global object outside of any function, and each global variable you create is a property of that object. In the browser, for convenience, the global variable is usually referred to by window. The following code shows how to create a global variable:
Myglobal = "Hello"; Antipatternconsole.log (Myglobal); "Hello" Console.log (Window.myglobal); "Hello" Console.log (window["Myglobal"]); "Hello" Console.log (This.myglobal); "Hello
Problems with global variables
The problem with global variables is that he shares all of your code or a page. They are under the same namespace, which usually causes variable name collisions – Two variables of the same name, but it does have a different use.
It is common to introduce some other people's code in some pages, such as:
- Third-party JS Library
- AD Partner's script
- Third-party user behavior analysis or statistical scripting
- Different components, buttons, etc.
Join one of the third-party components defines a global variable: result. Then in your program, a global variable result is also defined. The final result overrides the result before the point, so that the third-party script stops working.
Therefore, in order to be friendly to other scripts, the less global variables are used in one page the better. There are some ways to tell you how to reduce global variables, such as using namespaces, or self-executing anonymous functions, but the best way to avoid global variables is to use the VAR keyword to declare variables.
Because of the two features of JavaScript, creating a global variable is very simple. First, you can use a variable that is not even declared, and second, in JavaScript, all undeclared variables become a property of the global object (just like a declared global variable). Take a look at this example:
function sum (x, y) { result = x + y; return result;}
In this code, result is used without being declared, and the code works well, but after invoking the function, there is a global variable called result, which is the root of all the problems.
The solution to this problem is to use VAR:
function sum (x, y) { var result = x + y; return result;}
A bad habit is to use a chained method to assign a value when declaring a variable, when a is a local variable, but B becomes a global variable.
function foo () { var a=b=0; ....}
This is because the expression B = 0 Executes first, B is not declared at execution time, so B becomes the global variable, and then returns the value of the expression 0, to the declared variable a, in other words, as you entered: var a = (b=0);
If you have declared the variable, then the assignment of this chain is not a problem:
function foo () {var, a, b; ...}
Another reason to avoid using global variables is to consider the portability of the program. If you want your code to work in a different environment, then using global variables is likely to conflict with global variables in the new system (perhaps no problem in the previous system).
Forget about the impact of Var
The difference between a global variable declared with VAR and a global variable that is not generated using VAR is the deletion:
Global variables created using the Var declaration cannot be deleted. Global variables that are not declared with Var can be deleted. This means that the global variables that are not generated using the Var declaration are not real variables, they are just properties of the global object. Properties can be deleted through delete, but variables are not:
Define three Globalsvar Global_var = 1;global_novar = 2; Antipattern (function () { global_fromfunc = 3;//Antipattern} ()); Attempt to deletedelete Global_var; Falsedelete Global_novar; Truedelete Global_fromfunc; True //test the deletiontypeof Global_var;//"number" typeof Global_novar;//"undefined" typeof Global_fromfunc; /"Undefined"
In the strict mode of ES5, assigning a value to a declared variable will give an error.
Reading Global objects
In the browser, you can read the Global object through the window variable (unless you redefine the window object inside the function). But in some environments, it may not be called window, so you can use the following code to get the global object:
var global = (function () { return this;}) ();
The reason that this can be obtained to the global object is inside the function, which points to the global object. But this will not work in the strict mode of ES5, you need to adapt some other modes. When you develop your own library, you can encapsulate your code in an immediate function and pass this as a parameter.
Single var mode
At the top of your code just with a var keyword, there are the following benefits:
- For all the variables you need, you can see them all in one place.
- Avoid using a variable that is not defined
- Help you remember the declared variables, reduce the global variables
- More streamlined code
Writing is simple:
function func () { var a = 1, b = 2, sum = a + b, myobject = {}, I, J; function Body ...}
Declare multiple variables with a var and a comma. Assigning a default value to a variable at the time of declaration is also good practice, avoiding some logic errors and improving the readability of your code. When you read the code, you can also easily guess the purpose of the variable based on the default value of the variable.
You can also do some real work when declaring variables, such as Sum = a + B; In addition, you can save a reference to a DOM element in a variable when you manipulate the DOM element:
function Updateelement () { var el = document.getElementById ("result"), style = El.style; Do something with El and style ...}
The abused Var
JavaScript allows you to have multiple var statements inside a function, but it behaves as if it were declared at the top of the function. This feature causes some strange logic problems when you use a variable and then declare the variable later. For JavaScript, as long as the variable is in the same scope, it is assumed to be declared, even if it is used before the Var statement. Take a look at this example:
myname = "global"; Global variablefunction func () { alert (myname);//"undefined" var myname = "local"; alert (myname); "Local"}func ();
In this example, you might expect to pop up global for the first time, and a second pop-up of local. Because the first time there is no use VAR declaration myname, this is supposed to be a global variable myname, the second declaration, and then alert should be the local value. In fact it is not so, as long as you appear in the function of the Var myname, then JS think you declare this variable in this function, but when reading the value of this variable, because the VAR statement has not been executed, so it is undefined, very strange logic. The above code is equivalent to:
myname = "global"; Global variablefunction func () { var myname;//Same as-var myname = undefined; alert (myname); "Undefined" myname = "local"; alert (myname); "Local"}func ();
Let's explain this phenomenon, in the parsing of the code, in two steps, the first step is to deal with the declaration of the variable function, which processes the context of the entire code. The second step is to create the function expression and undefined variables when the code is run. In fact, we are only assuming this concept, which is not in the ECMAScript specification, but this behavior is often explained in this way.
For loop
In the For loop you will iterate over some array elements or some HTML elements. The For loop often does this:
for (var i = 0; i < myarray.length; i++) { //does something with Myarray[i]}
The problem with this writing is that the length of the array is computed for each iteration, especially if the parameter is not an array but a set of HTML elements that will degrade the performance of your program. The collection of HTML elements is on the page, which can be time consuming to find the corresponding element on the page every time. So for the For loop, you need to save the length of the array beforehand, so write:
for (var i = 0, max = myarray.length; i < Max; i++) { //does something with Myarray[i]}
This caches the length of the parameter and does not have to look for the calculation at each iteration. When looking for a collection of HTML elements, the length of the cache parameter can lead to considerable performance gains, with Safari up to twice times faster and 190 times times faster under IE7. It is important to note that when you need to manipulate the number of DOM elements, you certainly want this value to be updated at any time rather than as a constant.
Using the single var pattern below, you can also refer to Var outside of the loop:
function Looper () { var i = 0, max, myarray = []; // ... for (i = 0, max = myarray.length; i < Max; i++) { //does something with Myarray[i] }}
This pattern can enhance the continuity of the entire code, but the downside is that it's not that easy to copy and paste when you refactor the code. For example, if you want to use this loop in other functions, you need to make sure that I and Max are processed in the new function (and perhaps you need to delete this).
There are two points that can be optimized for this function: One less variable (max is not required), and 0, and a number compared to 0 is faster than the other number.
So it can be written as:
var i, myarray = [];for (i = myarray.length; i--;) { //do something with Myarray[i]}
For the 2nd:
var myarray = [], i = Myarray.length;while (i--) { //do something with Myarray[i]}
This is the optimization of two relatively small points. In addition, JSLint may have an opinion about I –.
For-in Cycle
The for-in loop is used to iterate over objects that are not arrays. Using for-in loops is also usually an enumeration.
Technically, you can also use for-in to loop an array, because arrays are also objects, but not recommended. If the array has some custom extension functions, then an error occurs. In addition, the order of object properties is not deterministic in the for-in loop. Therefore, it is better to use the normal loop to loop the array with for-in to loop the object.
In the process of looping an object, it is important to use the hasOwnProperty () method to verify whether the property of the object itself or the properties on the prototype chain.
Take a look at this example below.
The Objectvar man = { hands:2, legs:2, heads:1}; Somewhere else in the code//a method is added to all objectsif (typeof Object.prototype.clone = = = "undefined") { Object.prototype.clone = function () {};}
In this example, we have a simple object literal called man. The object prototype has a useful clone () method in place before or after other man definitions. Because of the reason for the prototype chain, all objects are automatically given this method. In order to present the Clone method when enumerating the man objects, you need to use the hasOwnProperty method to differentiate. If there is no difference from the method of the prototype chain, then there will be some unexpected things happen:
1.//for-in Loopfor (var i in mans) { if (Man.hasownproperty (i)) {//filter Console.log (i, ":", Man[i]); } }/* result in the consolehands:2legs:2heads:1*///2.//antipattern://for-in loop without checking hasownproperty () F or (var i in Mans) { console.log (i, ":", Man[i]);} /*result in the Consolehands:2legs:2heads:1clone:function () */
Another way to use this is as follows:
for (var i in mans) { if (Object.prototype.hasOwnProperty.call (man, i)) {//filter Console.log (i, ":", Man[i]);
}}
The benefit of this writing is that the man can be prevented from redefining the conflict caused by the hasOwnProperty method. If you don't want to write such a long string, you can do the following:
var i, Hasown = Object.prototype.hasownproperty;for (i in Mans) { if (Hasown.call (man, i)) {//filter Console.log ( I, ":", Man[i]);} }
Strictly speaking, it is not a mistake to apply hasownproperty. Depending on the difficulty of the task and how confident you are with the code, you can also use this direct loop. But when you're not sure, it's best to use this method to test it.
Another format change (does not pass the JSLint check), remove the curly brace for the for, and then put the if on the same line. The benefits of doing this can make the loop body more prominent and less indented:
WARNING:DOESN ' t pass Jslintvar i, Hasown = Object.prototype.hasownproperty;for (i in Mans) if (Hasown.call (man, i)) {/ /filter Console.log (i, ":", Man[i]);}
Do not extend the built-in prototypes
Extending the constructor of the prototype can provide some very powerful features, but sometimes he is too powerful.
Sometimes you will expand the prototype method of object (), Array (), Fucntion (), which will cause maintainability problems, because it will make your code less portable. When other developers use your code, they may only need native methods and do not require additional functionality.
In addition, you add the method, if the loop is not using the hasOwnProperty method will be traversed, this will be confusing.
Therefore, it is best not to extend the basic object. Unless the following is the case:
- You are sure that in the future according to the ECMAScript specification, the browser will add the corresponding prototype method, then it is possible, you just realized this feature in advance.
- You are certain that the method you want to implement does not exist – sometimes it is possible to implement it elsewhere in the code, or some browser support, which is not possible.
- have very clear documentation and have communicated with team members
If under these circumstances, then you can add, preferably in the following form:
if (typeof Object.prototype.myMethod!== "function") { Object.prototype.myMethod = function () { // Implementation ... };}
Cond...
How to write high-quality JavaScript code