Specifically, there are some elements of writing high-quality JavaScript, such as avoiding global variables, using single variable declarations, precaching length in loops, following code reading, and more.
This summary also includes some habits that are less relevant to code, but more relevant to overall code creation, including writing API documentation, performing peer reviews, and running JSLint. These habits and best practices can help you write better, easier to understand and maintain code that you'll be proud to look back on months or years from now.
Writing Maintainable Code
Fixing software bugs is expensive, and over time, the cost of these bugs will also increase, especially when these bugs lurk and slowly appear in the past in released software. It's best to fix a bug as soon as you find it, while the problem your code is trying to solve is still clear in your mind. Otherwise, you move on to other tasks and forget about that particular piece of code, and revisiting that code some time later requires:
Take the time to learn and understand the problem
Time is spent understanding the problem code that should be solved
There is also a problem, especially for large projects or companies, the guy who fixes the bug is not the person who wrote the code (and the person who discovered the bug and the person who fixed the bug are not the same person). Therefore, you must reduce the time it takes to understand code, whether it was code you wrote some time ago or code written by other members of the team. This is about the bottom line (revenue) and developer happiness, because we should be building new and exciting things instead of spending hours and days maintaining legacy code.
Another fact about software development life is that reading code takes much longer than writing it. Sometimes, when you focus and think deeply about a problem, you can sit down and write a lot of code in an afternoon.
Your code will work very quickly, but as the application matures, a lot of other things will happen, which will require you to review, modify, and adjust. For example:
A bug is exposed
New features are added to the application
The program works in a new environment (for example, a new browser appears on the market)
Code Repurpose
Code has to be completely re-written from scratch, or ported to another architecture or even in another language
Due to these changes, code that few people took hours to write ends up taking weeks to read. . This is why creating maintainable code is critical to the success of your application.
Maintainable code means:
Readable
Consistent
Predictable
Looks like the same person wrote it
Documented
Minimal global variables (Minimizing Globals)
JavaScript manages scope through functions. Variables declared inside a function are only available inside the function and are not available outside the function. On the other hand, global variables are declared outside any function or simply used without being declared.
Each JavaScript environment has a global object that can be accessed when you use this outside any function. Every variable you create becomes a property of this global object. In the browser, for convenience, the global object has an additional property called window, which (usually) points to the global object itself. The following code snippet shows how to create and access global variables in the browser environment:
myglobal = "hello"; // Not recommended
console.log(myglobal); // "hello"
console.log(window.myglobal); // "hello"
console.log(window["myglobal"]); // "hello"
console.log(this.myglobal); // "hello"
The Problem with Global Variables The problem with global variables is that these global variables are shared by all the code in your JavaScript application and web page, and they live in the same global namespace. So when two different parts of the program define global variables with the same name but different functions, naming conflicts are inevitable.
It is also common for web pages to contain code that was not written by the developer of the page, for example:
Third-party JavaScript library
Advertiser’s script code
Third-party user tracking and analysis script code
Different types of widgets, logos and buttons
For example, the third-party script defines a global variable called result; then, also define a global variable called result in your function. The result is that the later variables overwrite the previous ones, and the third-party script suddenly burps!
Therefore, if you want to be a good neighbor with other scripts, it is important to use global variables as little as possible. Some strategies for reducing global variables are mentioned later in the book, such as namespace mode or automatic function execution immediately, but the most important thing to reduce global variables is to always use var to declare variables.
Due to two characteristics of JavaScript, it is surprisingly easy to create global variables unconsciously. First, you can use variables without even declaring them; second, JavaScript has the concept of implicit globals, which means that any variable you don't declare becomes a global object property. Refer to the code below:
function sum(x, y) {
// Not recommended: implicit global variable
result = x y;
return result;
}
The result in this code is not declared. The code still works fine, but after calling the function you end up with an extra global namespace, which can be a source of problems.
The rule of thumb is to always use var to declare variables, as demonstrated by the improved sum() function:
function sum(x, y) {
var result = x y;
return result;
}
Another creation A counterexample to implicit global variables is partial var declaration using task chains. In the following snippet, a is a local variable but b is a global variable, which may not be what you want to happen:
// Counterexample, do not use
function foo() {
var a = b = 0;
// ...
}
The reason why this phenomenon occurs is that this assignment from right to left, first of all, is the assignment expression b = 0, in which case b is undeclared. The return value of this expression is 0, and then this 0 is assigned to the local variable a defined by var. In other words, it's as if you typed:
var a = (b = 0);
If you are ready to declare the variable, it is better to use chain allocation without any unexpected consequences. Global variables, such as:
function foo() {
var a, b;
// ... a = b = 0; // Both local variables
}
However, another reason to avoid global variables is portability. If you want your code to run in a different environment (host), using global variables is on thin ice, because you will inadvertently overwrite host objects that do not exist in your original environment (so you thought the name can be used safely, but in fact The above does not apply in some cases).
Side Effects When Forgetting var
There is a small difference between implicit global variables and explicitly defined global variables, which is the ability to leave variables undefined through the delete operator.
Global variables created through var (created in any program outside of functions) cannot be deleted.
Implicit global variables created without var (regardless of whether they are created in a function) can be deleted.
This shows that, technically, implicit global variables are not really global variables, but they are properties of the global object. Attributes can be deleted through the delete operator, but variables cannot:
// Define three global variables
var global_var = 1;
global_novar = 2; // Negative teaching material
(function () {
global_fromfunc = 3; // Negative Textbook
}());
// Try to delete
delete global_var; // false
delete global_novar; // true
delete global_fromfunc; // true
// Test this Remove
typeof global_var; // "number"
typeof global_novar; // "undefined"
typeof global_fromfunc; // "undefined"
Copy code
In ES5 strict mode, undeclared An error will be thrown when working with variables (like the two negative examples in the previous code snippet).
Access to the Global Object
In the browser, the global object can be accessed anywhere in the code through the window attribute (unless you do something outrageous, such as declaring a name is a local variable of window). But in other circumstances, this convenience property might be called something else (or even not available in the program). If you need to access the global object without a hard-coded window identifier, you can do the following in a function scope at any level:
var global = (function () {
return this;
}());
This method can obtain the global object at any time, because it is called as a function in the function (not through new construction), and this always points to the global object. Actually this bug doesn't apply to ECMAScript 5 strict mode, so you have to take a different form when in strict mode. For example, if you are developing a JavaScript library, you can wrap your code in an immediate function, and then pass a reference to this from the global scope as a parameter of your immediate function.
Single var Pattern
Using a single var statement at the top of a function is a more useful form. The benefits are:
Provides a single place to find all the local parts needed for the function. Variables
prevent logical errors when variables are used before definition
helps you remember declared global variables, so there are fewer global variables //zxx: I am a little confused here...
Less code (Type, value, and single-line completion)
The single var form looks like the following:
function func() {
var a = 1,
b = 2,
sum = a b,
myobject = {},
i ,
j;
// function body...
}
You can use one var statement to declare multiple variables, separated by commas. It's a good idea to initialize variables and values at the same time like this. This prevents logic errors (the initial value of all uninitialized but declared variables is undefined) and increases the readability of the code. After you see the code, you can know the general purpose of these variables based on the initialized values, such as whether they are to be used as objects or as integers.
You can also do some actual work when declaring, such as sum = a b in the previous code. Another example is when you use DOM (Document Object Model) reference, you can use a single var DOM references are specified together as local variables, as shown in the following code:
function updateElement() {
var el = document.getElementById("result"),
style = el.style;
// Use el and style to do something else...
}
Hoisting: A Problem with Scattered vars (Hoisting: A Problem with Scattered vars)
In JavaScript, you can declare multiple var statements anywhere in a function, and they It behaves as if it were declared at the top of the function, a behavior called hoisting. Logic errors may occur when you use a variable and then redeclare it later in a function. For JavaScript, as long as your variable is in the same scope (same function), it is considered declared, even when it is used before the var declaration. Look at the following example:
// Counterexample
myname = "global"; // Global variable
function func() {
alert(myname); // "undefined"
var myname = "local";
alert(myname); // "local"
}
func();
In this example, you may think that the first alert pops up "global" and the second alert pops up "loacl". This expectation is understandable, because at the time of the first alert, myname was not declared. At this time, the function must naturally look at the global variable myname, but this is not actually how it works. The first alert will pop up "undefined" because myname is treated as a local variable of the function (even though it is declared later), and all variable declarations are suspended to the top of the function. Therefore, to avoid this confusion, it is best to declare in advance all the variables you want to use.
The above code snippet may behave like this:
myname = "global"; // global variable
function func() {
var myname; // Equivalent to -> var myname = undefined;
alert(myname); // "undefined"
myname = "local";
alert(myname); // "local"}
func();
For completeness, let's mention it again Something a little more complicated at the execution level. Code processing is divided into two stages. The first stage is variable, function declaration, and parameter creation in normal format. This is a stage of parsing and entering context. The second phase is code execution, where function expressions and unqualified identifiers (for declared variables) are created. However, for practical purposes, we will adopt the concept of "hoisting", which is not defined in the ECMAScript standard and is generally used to describe behavior.
for loop (for Loops)
In a for loop, you can loop through the values of arrays or array-like objects, such as arguments and HTMLCollection objects. The usual loop form is as follows:
//The second best loop
for (var i = 0; i < myarray.length; i ) {
// Use myarray[i] to do something
}
This form The disadvantage of looping is that the length of the array must be obtained each time it is looped. This will reduce your code, especially when myarray is not an array, but an HTMLCollection object.
HTMLCollections refers to the objects returned by DOM methods, for example:
document.getElementsByName()
document.getElementsByClassName()
document.getElementsByTagName()
There are other HTMLCollections that were introduced before the DOM standard and are still there used. There are:
document.images: All image elements on the page
document.links: All a tag elements
document.forms: All forms
document.forms[0].elements: All fields in the first form on the page
The trouble with collections is that they query the underlying document (HTML page) in real time. This means that every time you access the length of any collection, you have to query the DOM in real time, and DOM operations are generally expensive.
This is why it is good form to cache the length of an array (or collection) when you loop over values, as shown in the following code:
for (var i = 0, max = myarray.length; i < max; i ) {
// Use myarray[ i] Do something
}
This way, during this loop, you only retrieve the length value once.
Cache the length of HTMLCollections when looping to retrieve content is faster in all browsers, between 2x (Safari3) and 190x (IE7). //zxx: This data seems to be very old, just for reference
Note that when you explicitly want to modify the collection in the loop (for example, adding more DOM elements), you may prefer length update instead of constant.
With the single var form, you can pull the variable out of the loop, like this:
function looper() {
var i = 0,
max,
myarray = [];
// ...
for (i = 0, max = myarray.length; i < max; i ) {
// Do something with myarray[i]
}
}
This form has the benefit of consistency because you stick to a single var form. The downside is that when refactoring code, copying and pasting the entire loop is a bit difficult. For example, if you copy a loop from one function to another, you have to make sure that you can introduce i and max into the new function (if they are not useful here, you will most likely have to delete them from the original function) Lose).
The last adjustment to the loop is to replace i with one of the expressions below.
i = i 1
i = 1
JSLint prompts you to do this because and - promotes "excessive trickiness". //zxx: This is more difficult to translate. I think the intention is to make the code more difficult.
If you ignore it directly, the plusplus option of JSLint will be false (the default is default).
There are also two variations, which are slightly improved because:
One less variable (no max)
Counting down to 0 is usually faster because it takes more time to compare with 0 More efficient than comparing with array length or other things that are not 0
//The first variation:
var i, myarray = [];
for (i = myarray.length; i–-;) {
// Use myarray[i ]Do something
}
//The second way is to use a while loop:
var myarray = [],
i = myarray.length;
while (i–-) {
// Use myarray[i] to do something
}
These small improvements are only reflected in performance, and JSLint will complain about using i--.
for-in loops (for-in Loops)
For-in loops should be used to traverse non-array objects. Using for-in to loop is also called "enumeration".
Technically, you can use a for-in loop over an array (because arrays are objects in JavaScript), but this is not recommended. Because if the array object has been enhanced with custom functions, logic errors may occur. In addition, in for-in, the order (sequence) of the attribute list is not guaranteed. So it's best to use a normal for loop for arrays and a for-in loop for objects.
There is a very important hasOwnProperty() method, which can filter out the properties from the prototype chain when traversing the object properties.
Consider the following piece of code:
// Object
var man = {
hands: 2,
legs: 2,
heads: 1
};
// somewhere in the code
// add a method Given all objects
if (typeof Object.prototype.clone === "undefined") {
Object.prototype.clone = function () {};
}
In this example, we have an object named man defined using an object literal. Somewhere after the man definition was completed, a useful method called clone() was added to the object prototype. This prototype chain is live, which means that all objects automatically have access to the new methods. In order to avoid the clone() method when enumerating man, you need to apply the hasOwnProperty() method to filter prototype properties. If no filtering is done, the clone() function will be displayed, which is undesirable in most cases.
// 1.
// for-in Loop
for (var i in man) {
if (man.hasOwnProperty(i)) { // Filter
console.log(i, ":", man[i]);
}
}
/* Console display result
hands: 2
legs: 2
heads: 1
*/
// 2.
// reverse side Example:
// for-in loop without checking hasOwnProperty()
for (var i in man) {
console.log(i, ":", man[i]);
}
/*
The console displays the result
hands: 2
legs: 2
heads: 1
clone: function()
*/
Another way to use hasOwnProperty() is to cancel the method on Object.prototype. For example:
for (var i in man) {
if (Object.prototype.hasOwnProperty.call(man, i)) { // Filter
console.log(i, ":", man[i]);
}
}
The advantage is to avoid naming conflicts when the man object redefines hasOwnProperty. Also avoiding all methods of long property lookup objects, you can "cache" it using local variables.
var i, hasOwn = Object.prototype.hasOwnProperty;
for (i in man) {
if (hasOwn.call(man, i)) { // Filter
console.log(i, ":", man[i]);
}
}
Strictly speaking, not using hasOwnProperty() is not a mistake. Depending on the task and how confident you are in the code, you may be able to skip it to speed up the loop a bit. But when you are unsure about the current object's contents (and its prototype chain), adding hasOwnProperty() is safer.
Formatting changes (not passed by JSLint) will simply ignore the curly braces and put the if statement on the same line. The advantage is that the loop statement reads like a complete idea (each element has its own attribute "X", use "X" to do something):
// Warning: Failed to pass JSLint detection
var i, hasOwn = Object.prototype.hasOwnProperty;
for (i in man) if (hasOwn.call(man, i)) { // Filter
console.log(i, ":", man[i]);
}
(Not) Augmenting Built-in Prototypes)
Augmenting the prototype attribute of a constructor is a very powerful way to add functionality, but sometimes it is too powerful.
It is tempting to add built-in constructor prototypes (such as Object(), Array(), or Function()), but this seriously reduces maintainability because it makes your code unpredictable. Other developers who use your code will probably prefer to use the built-in JavaScript methods to work continuously, rather than the methods you add.
Also, properties added to the prototype may cause it to be displayed in the loop when the hasOwnProperty attribute is not used, which can cause confusion.
Therefore, it is best not to add built-in prototypes. You can specify a rule to make exceptions only if the following conditions are met:
It is expected that future versions of ECMAScript or JavaScript implementations will always implement this functionality as a built-in method. For example, you could add the methods described in ECMAScript 5 until browsers catch up. In this case, you just define useful methods ahead of time.
If you check that your custom property or method no longer exists - perhaps it is already implemented elsewhere in the code or is already part of your supported browser JavaScript engine.
You clearly documented and communicated changes to the team.
If these three conditions are met, you can make customized additions to the prototype in the following form:
if (typeof Object.protoype.myMethod !== "function") {
Object.protoype.myMethod = function () {
// Implementation...
};
}
switch Pattern
You can enhance readability and robustness by using a switch statement similar to the following:
var inspect_me = 0,
result = '';
switch ( inspect_me) {
case 0:
result = "zero";
break;
case 1:
result = "one";
break;
default:
result = "unknown";
}
The style convention followed in this simple example is as follows:
Align each case and switch (except for brace indentation rules)
Code indentation in each case
Each case ends with break clear
Avoid penetration (break is ignored intentionally). If you are very convinced that through-lines are the best approach, be sure to document this as they may look wrong to some readers.
End switch with default: ensure there is always a sane result, even if no case matches.
Avoiding Implied Typecasting
JavaScript variables will be implicitly type converted when compared. That's why something like: false == 0 or "" == 0 returns true. To avoid confusing implicit type conversions, always use the === and !== operators when you compare value and expression types.
var zero = 0;
if (zero === false) {
// Not executed because zero is 0, not false
}
// Negative example
if (zero == false) {
// Executed...
}
There is another thought that == is enough === is redundant. For example, when you use typeof you know it will return a string, so there is no reason to use strict equality. However, JSLint requires strict equality, which makes the code look more consistent and reduces the energy consumption when reading the code. ("Is == intentional or an oversight?")
Avoiding eval()
If you use eval() in your current code, remember the mantra "eval() is the devil". This method accepts any string and processes it as JavaScript code. When the code in question is known in advance (not determined at runtime), there is no reason to use eval(). If the code is generated dynamically at runtime, there is a better way to achieve the same goal without using eval. For example, it would be better and simpler to access dynamic properties using square bracket notation:
// Negative example
var property = "name";
alert(eval("obj." property));
// Better
var property = "name ";
alert(obj[property]);
Using eval() also brings security risks, because the code being executed (for example, from the network) may have been tampered with. This is a very common negative lesson when dealing with JSON responses from Ajax requests. In these cases, it's best to use JavaScript's built-in methods to parse the JSON response to ensure safety and efficiency. If the browser does not support JSON.parse(), you can use the library from JSON.org.
It is also important to remember that passing strings to the setInterval(), setTimeout() and Function() constructors is, in most cases, similar to using eval() and should therefore be avoided. Behind the scenes, JavaScript still needs to evaluate and execute the string you pass to the program:
// Negative example
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);
// Better
setTimeout(myFunc, 1000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000);
Use new The Function() construct is similar to eval() and should be approached with caution. This can be a powerful construct, but is often misused. If you absolutely must use eval(), you may consider using new Function() instead. There is a small potential benefit, because the code evaluation in the new Function() operates in the local function scope, so any variables defined by var that are evaluated in the code will not automatically become global variables. Another way to prevent automatic global variables is to wrap the eval() call into an immediate function.
Consider the following example, where only un pollutes the namespace as a global variable.
console.log(typeof un); // "undefined "
console.log(typeof deux); // "undefined"
console.log(typeof trois); // "undefined"
var jsstring = "var un = 1; console.log(un );";
eval(jsstring); // logs "1"
jsstring = "var deux = 2; console.log(deux);";
new Function(jsstring)(); / / logs "2"
jsstring = "var trois = 3; console.log(trois);";
(function () {
eval(jsstring);
}()); / / logs "3"
console.log(typeof un); // number
console.log(typeof deux); // "undefined"
console.log(typeof trois); // "undefined "
Another difference between eval() and Function constructs is that eval() can interfere with the scope chain, while Function() is more secure. No matter where you execute Function(), it only sees the global scope. So it can very well avoid local variable pollution. In the following example, eval() can access and modify variables in its outer scope, which Function cannot do (note that using Function and new Function are the same).
(function () {
var local = 1 ;
eval("local = 3; console.log(local)"); // logs "3"
console.log(local); // logs "3"
}());
(function () {
var local = 1;
Function("console.log(typeof local);")(); // logs undefined
}());
Number Conversions with parseInt())
Using parseInt() you can get a numeric value from a string. The method accepts another radix parameter, which is often omitted, but shouldn't be. There may be problems when the string starts with "0". For example, when entering the form field part of the time, in ECMAScript 3, strings starting with "0" are treated as octal, but this has been done in Changed in ECMAScript 5. To avoid contradictions and unexpected results, always specify radix arguments.
var month = "06",
year = "09";
month = parseInt(month, 10);
year = parseInt(year, 10);
In this example, if you ignore the base parameter, such as parseInt (year), the returned value will be 0, because "09" is treated as octal (such as executing parseInt(year, 8)), and 09 is not a valid number in octal.
The replacement method is to convert the string into a number, including:
"08" // The result is 8
Number("08") // 8
These are usually faster than parseInt() because the parseInt() method, as the name implies, is not Simple parsing and conversion. However, if you want to enter, for example, "08 hello", parseInt() will return a number, and otherwise end up with NaN.
Coding Conventions
It is important to establish and follow coding conventions. This makes your code consistent, predictable, and easier to read and understand. A new developer joining the team can read through the specifications, understand the code written by other team members, and get started working faster.
Many heated debates occur in meetings or on mailing lists, often over specific aspects of coding standards (such as code indentation, tab or space). If you are the one proposing the adoption of a norm in your organization, be prepared to face a variety of objections or strong-sounding opinions. Remember, establishing and following a code steadfastly is much more important than getting hung up on the details of the code.
Indentation
Code is basically unreadable without indentation. The only bad thing is inconsistent indentation, because it looks like it's following a specification, but may lead to confusion and surprises along the way. It's important to use indentation properly.
Some developers prefer tab indentation because anyone can adjust their editor to display tabs with their preferred number of spaces. Some people like spaces - usually four, which doesn't matter as long as everyone on the team follows the same norm. This book, for example, uses four spaces for indentation, which is also the default indentation in JSLint.
What should be indented? The rule is simple - what goes inside the curly braces. This means function bodies, loops (do, while, for, for-in), if, switch, and object properties in object literals. The following code is an example of using indentation:
function outer (a, b) {
var c = 1,
d = 2,
inner;
if (a > b) {
inner = function () {
return {
r: c - d
};
};
} else {
inner = function () {
return {
r: c d
};
};
}
return inner;
}
Curly Braces {} (Curly Braces)
Curly brackets (also known as braces, the same below) should always be used, even when they are optional. Technically, braces are not needed if there is only one statement in an in or for, but you should always use them anyway. This makes the code more consistent and easier to update.
Imagine you have a for loop with only one statement. You can ignore the curly braces without parsing errors.
// Bad example
for (var i = 0; i < 10; i = 1)
alert(i);
But, what if, later, another line of code is added to the main loop?
// Bad example
for (var i = 0; i < 10; i = 1)
alert(i);
alert(i " is " (i % 2 ? "odd" : "even"));
The second alert is already outside the loop, the indentation may have deceived you. For long-term planning, it is best to always use curly braces, which are equivalent to one line of code:
// Good example
for (var i = 0; i < 10; i = 1) {
alert(i);
}
If conditions are similar:
// Bad
if (true)
alert(1);
else
alert(2);
// OK
if (true) {
alert(1);
} else {
alert(2);
}
Opening Brace Location)
Developers have different preferences for the location of the opening brace - in The same line or the next line.
if (true) {
alert("It's TRUE!");
}
//or
if (true)
{
alert("It's TRUE!");
}
In this example, benevolence sees benevolence and wisdom sees wisdom, but there are also cases where different positions of brackets will lead to different behaviors. This is because of the semicolon insertion mechanism - JavaScript is not picky and will make up for it when you choose not to end a line of code with a semicolon. This behavior can cause trouble, for example when you return an object literal and the opening bracket is on the next line:
// Warning: Unexpected return value
function func() {
return
// The following code will not be executed
{
name : "Batman"
}
}
If you expect the function to return an object with a name attribute, you will be surprised. Because of the implicit semicolon, the function returns undefined. The previous code is equivalent to:
// Warning: Unexpected The return value of
function func() {
return undefined;
// The following code will not be executed
{
name : "Batman"
}
}
In short, always use curly braces and always put the statement before it on the same line:
function func() {
return {
name : "Batman"
};
}
Note about semicolons: Just like using curly braces, you should always use semicolons, even though they can be created implicitly by the JavaScript parser. This not only promotes more scientific and rigorous code, but also helps resolve areas of confusion, as the previous example shows.
White Space (White Space)
The use of white space also helps to improve the readability and consistency of the code. When writing English sentences, spaces are used after commas and periods. In JavaScript, you can follow the same logic by adding space after a list-like expression (equivalent to a comma) and a closing statement (relative to the completion of the "idea").
Suitable places for using spaces include:
The semicolon-separated part of a for loop: such as for (var i = 0; i < 10; i = 1) {...}
for loop Multiple variables (i and max) initialized in: for (var i = 0, max = 10; i < max; i = 1) {...}
After the comma that separates the array items: var a = [1, 2, 3];
After the comma of the object attribute and the colon that separates the attribute name and attribute value: var o = {a: 1, b: 2};
Qualified function parameters: myFunc(a , b, c)
Before the curly braces of the function declaration: function myFunc() {}
After the anonymous function expression function: var myFunc = function () {};
Use spaces to separate all Operators and operands are another good use, which means, -, *, =, <, >, <=, >=, ===, !==, &&, ||, Spaces are required before and after = etc.
// Loose and consistent spacing
// Make The code is more readable
// Makes it more "breathable"
var d = 0,
a = b 1;
if (a && b && c) {
d = a % c;
a = d;
}
// Negative example
// Missing or uneven spacing
// Makes the code confusing
var d = 0,
a = b 1;
if (a&&b&&c) {
d=a % c;
a = d;
}
The last space you need to pay attention to is the spacing between curly braces. It is best to use spaces:
before the left curly brace ({) of functions, if-else statements, loops, and object literals
the right curly brace (}) between else or while
spaces are used One drawback is that the file size increases, but compression does not have this problem.
An often overlooked aspect of code readability is the use of vertical whitespace. You can use blank lines to separate units of code, much like paragraphs are separated in literature.
Naming Conventions
Another way to make your code more predictable and maintainable is to adopt naming conventions. This means you need to name your variables and functions in the same way.
The following are some suggested naming conventions. You can adopt them as they are or adjust them according to your own preferences. Likewise, following the norm is more important than what the norm is.
Write constructors in capital letters (Capitalizing Constructors)
JavaScript does not have classes, but there is a constructor called by new:
var adam = new Person();
Because the constructor is still just a function , just looking at the function name can help tell you whether this should be a constructor or a normal function.
When naming constructors, the first letter of the capital letter has a suggestive effect. Functions and methods named in lowercase should not be called with new:
function MyConstructor() {...}
function myFunction() {...}
Separating Words )
When your variable or function name has multiple words, it is best to follow a unified standard for word separation. There is a common practice called "Camel case (Camel) naming method", which is to lowercase the words. Capitalize the first letter of each word.
For constructors, you can use upper camel case, such as MyConstructor(). For function and method names, you can use lower camel case, such as myFunction(), calculateArea() and getFirstName().
What if the variable is not a function? Developers often use camelCase notation, but an alternative is to lowercase words followed by underscores: for example, first_name, favorite_bands, and old_company_name. This notation helps you visually distinguish functions from other identifiers - prototypes and objects.
ECMAScript properties and methods all use Camel notation, although multi-word property names are rare (lastIndex and ignoreCase properties of regular expression objects).
Other Naming Patterns
Sometimes, developers use naming conventions to compensate for or replace language features.
For example, there is no way to define constants in JavaScript (although there are some built-in ones like Number, MAX_VALUE), so developers use the all-capitalization convention to name variables that will not change during the life cycle of the program, such as:
// Precious constants, only visible from a distance
var PI = 3.14,
MAX_WIDTH = 800;
Copy code
There is another convention of all capital letters: global variable names are all capital letters. Naming global variables in all caps reinforces the practice of reducing the number of global variables while making them easily distinguishable.
Another way to use specifications to simulate functionality is with private members. Although it is possible to achieve true privateness in JavaScript, developers find it easier to just use an underscore prefix to indicate a private property or method. Consider the following example:
var person = {
getName: function () {
return this._getFirst() ' ' this._getLast();
},
_getFirst: function () {
// ...
},
_getLast: function () {
// ...
}
};
In this example, getName() represents a public method and a partially stable API. And _getFirst() and _getLast() indicate private. They are still normal public methods, but the underscore prefix is used to warn users of the person object that these methods are not guaranteed to work in the next version and cannot be used directly. Note that JSLint does not use the underscore prefix unless you set the noman option to :false.
The following are some common _private specifications:
Use a trailing underscore to indicate private, such as name_ and getElements_()
Use an underscore prefix to indicate _protected attributes, and two underscore prefixes to indicate __private (Private) attributes
Some built-in variable attributes in Firefox do not belong to the technical part of the language, and are represented by two leading underscores and two trailing underscores, such as: __proto__ and __parent__.
Writing Comments
You must comment your code, even if no one else will touch it like you. Usually, when you study a problem in depth, you will clearly know what the code is used for, but when you come back to it a week later, you must have spent a lot of brain cells to figure out how it works. of.
Obviously, comments cannot go to extremes: each separate variable or a separate line. However, you should generally document all functions, their parameters and return values, or any unusual techniques or methods. Remember that comments can give future readers of your code a lot of clues; readers need (without reading too much) just the comments and function attribute names to understand your code. For example, when you have five or six lines of program that perform a specific task, the reader can skip this detail if you provide a description of the purpose of the line and why it is there. There is no hard and fast rule about the ratio of comments to code, and some parts of the code (such as regular expressions) may have more comments than code.
The most important habit, but also the hardest to follow, is to keep comments up to date, because outdated comments are more misleading than no comments at all.
About the Author
Stoyan Stefanov is a Yahoo! web developer, author, contributor and technical reviewer of several O'Reilly books. He frequently speaks on web development topics at conferences and on his blog at www.phpied.com. Stoyan is also the creator of the smush.it image optimization tool, a YUI contributor, and the architect of Yahoo's performance optimization tool YSlow 2.0.
This article is reproduced from: http://www.zhangxinxu.com/wordpress/?p=1173
Original English text: http://net.tutsplus.com/tutorials/javascript-ajax/the-essentials-of- writing-high-quality-javascript/
Synchronization and conclusion
This article has been synchronized to the directory index: In-depth understanding of JavaScript series
In-depth understanding of JavaScript series of articles, including original creation, translation, and reprinting Other types of articles, if they are useful to you, please recommend and support them to give uncle the motivation to write.