Programming style

Overview

"Programming style" refers to the style rules for writing code. Different programmers often have different programming styles.

Some people say that the compiler's specification is called "grammar" (grammar), which programmers must abide by; and the part that the compiler ignores is called "programming style", which is free for programmers to choose. . This statement is not entirely correct. Programmers are free to choose their programming style, but a good programming style helps to write programs with higher quality, fewer errors, and easier maintenance.

Therefore, the choice of programming style should not be based on personal hobbies, familiarity, amount of typing and other factors, but should consider how to make the code as clear and readable as possible and reduce errors. What you choose is not a style you like, but a style that can clearly express your intentions. This is especially important for languages ​​like JavaScript with a high degree of grammatical freedom.

One thing that must be kept in mind is that if you choose a "programming style", you should stick to it and avoid mixing multiple styles. If you join someone else’s project, you should follow the existing style.

Indent

Both the space at the beginning of the line and the Tab key can produce code indentation (indent).

The Tab key can save the number of keystrokes, but different text editors display Tab differently. Some display four spaces, and some display two spaces. So some people think that the space bar can make the display effect more uniform.

No matter which method you choose, it is acceptable. All you have to do is to always stick to this choice. Don't use the Tab key for a while, and the space bar for a while.

Block

If the code body of the loop and judgment is only one line, JavaScript allows the block to omit the braces.

if (a) b();
c();

The original intent of the above code may be as follows.

if (a) {
  b();
  c();
}

However, the actual effect is as follows.

if (a) {
  b();
}
c();

Therefore, it is recommended to always use curly brackets to indicate blocks.

In addition, there are many different ways of writing the position of the brace at the beginning of the block. There are two most popular ones, one is the opening brace on a new line.

block;
{
  // ...
}

The other is the opening brace following the keyword.

block {
  // ...
}

Generally speaking, both writing methods are acceptable. However, JavaScript should use the latter, because JavaScript will automatically add a semicolon at the end of the sentence, causing some undetectable errors.

return;
{
  key: value;
}

// equivalent to
return;
{
  key: value;
}

The original intention of the above code is to return an object, but in fact it returns undefined because JavaScript automatically adds a semicolon after the return statement. In order to avoid this type of error, it needs to be written as follows.

return {
  key: value,
};

Therefore, do not start a new line with the curly brace at the beginning of the block.

Parentheses

Parentheses have two functions in JavaScript, one is for function calls, and the other is for grouping expressions.

// parentheses indicate function calls
console.log("abc");

// parentheses indicate a combination of expressions
(1 + 2) * 3;

It is recommended to use spaces to distinguish these two different brackets.

  1. It means that there is no space between the function name and the left parenthesis when the function is called.

  2. When the function is defined, there is no space between the function name and the left parenthesis.

  3. In other cases, there is a space between the syntax element in the previous position and the left parenthesis.

According to the above rules, the following writing is not standardized.

foo (bar)
return(a+b);
if(a === 0) {...}
function foo (b) {...}
function(x) {...}

The last line of the above code is an anonymous function, function is a syntax keyword, not a function name, so there should be a space between the opening parenthesis.

Semicolon at the end of the line

The semicolon indicates the end of a statement. JavaScript allows you to omit the semicolon at the end of the line. In fact, there are indeed some developers who never write a semicolon at the end of the line. However, due to the reasons to be discussed below, it is recommended not to omit this semicolon.

When semicolon is not used

First, in the following three cases, the grammar stipulates that there is no need to add a semicolon at the end.

(1) for and while loops

for (;;) {} // no semicolon

while (true) {} // no semicolon

Note that the do...while loop has a semicolon.

do {
  a--;
} while (a > 0); // semicolon cannot be omitted

(2) Branch statement: if, switch, try

if (true) {
} // no semicolon

switch () {
} // no semicolon

try {
} catch {
} // no semicolon

(3) Function declaration statement

function f() {} // no semicolon

Note that function expressions still need to use semicolons.

var f = function f() {};

In the above three cases, if a semicolon is used, there will be no error. Because the interpretation engine will interpret this semicolon as an empty statement.

Automatic addition of semicolon

Except for the three cases in the previous section, all statements should use semicolons. However, if the semicolon is not used, in most cases, JavaScript will be added automatically.

var a = 1;
// Equivalent to
var a = 1;

This grammatical feature is called "Automatic Semicolon Insertion" (ASI).

Therefore, some people advocate omitting the semicolon at the end of the sentence. The trouble is, if the beginning of the next line can be explained together with the end of this line, JavaScript will not automatically add a semicolon.

// equivalent to var a = 3
var a = 3;

// equivalent to'abc'.length
"abc".length;

// equivalent to return a + b;
return a + b;

// equivalent to obj.foo(arg1, arg2);
obj.foo(arg1, arg2);

// equivalent to 3 * 2 + 10 * (27 / 6)
3 * 2 + 10 * (27 / 6);

The above code will be explained in multiple lines together, and a semicolon will not be automatically added to each line. These examples are relatively easy to see, but the following example is not so easy to see.

x = y
(function () {
  // ...
})();

// Equivalent to
x = y(function () {...})();

Below are more examples where semicolons are not automatically added.

// The engine is interpreted as c(d+e)
var a = b + c(d + e).toString();

// The engine is interpreted as a = b/hi/g.exec(c).map(d)
// The slash in the regular expression will be used as a division operator
a = b / hi / g.exec(c).map(d);

// Interpreted as'b'['red','green'],
// That is, treat the string as an array and get the value by index
var a = "b"[("red", "green")].forEach(function (c) {
  console.log(c);
});

// Interpreted as function (x) {return x }(a++)
// That is to call the anonymous function, the result f is equal to 0
var a = 0;
var f = (function (x) {
  return x;
})(a++);

Only when the beginning of the next line and the end of this line cannot be explained together, the JavaScript engine will automatically add a semicolon.

if (a < 0) a = 0;
console.log(a);

// is equivalent to the following code,
// because 0console is meaningless
if (a < 0) a = 0;
console.log(a);

In addition, if the beginning of a line is the "increment" (++) or "decrement" (--) operator, a semicolon will be automatically added in front of them.

a = b = c = 1;

a;
++b - c;

console.log(a, b, c);
// 1 2 0

The reason why the above code will get the result of 1 2 0 is that a semicolon is automatically added before the increment and decrement operators. The above code is actually equivalent to the following form.

a = b = c = 1;
a;
++b;
--c;

If the four statements of continue, break, return and throw are directly followed by a newline character, a semicolon will be automatically added. This means that if the return statement returns the literal of an object, the opening brace must be written on the same line, otherwise the expected result will not be obtained.

return;
{
  first: "Jane";
}

// interpreted as
return;
{
  first: "Jane";
}

Because the automatic semicolon addition behavior of the interpretation engine is unpredictable, the semicolon at the end of the line should not be omitted when writing code.

There is another reason why the semicolon at the end should not be omitted. Some JavaScript code compressors (uglifier) ​​do not automatically add semicolons, so when they encounter an end without a semicolon, they will keep the code as it is instead of compressing it into a single line, making the compression unable to get the best results.

In addition, not writing the ending semicolon may cause script merge errors. Therefore, some code libraries will add a semicolon before the first line of statement.

var a = 1;
// ...

The above writing method can avoid the problem that when merging with other scripts, the last line of the script in the front does not have a semicolon, which may cause running errors.

Global Variables

The biggest grammatical disadvantage of JavaScript may be that global variables are readable and writable for any code block. This is very detrimental to the modularization and reuse of the code.

Therefore, it is recommended to avoid using global variables. If you have to use it, you can consider using capital letters to indicate the variable name, so that it is easier to see that this is a global variable, such as UPPER_CASE.

Variable declaration

JavaScript will automatically "hoist" variable declarations to the head of the block.

if (!x) {
  var x = {};
}

// Equivalent to
var x;
if (!x) {
  x = {};
}

This means that the variable x existed before the if code block. In order to avoid possible problems, it is best to put variable declarations at the head of the code block.

for (var i = 0; i < 10; i++) {
  // ...
}

// written as
var i;
for (i = 0; i < 10; i++) {
  // ...
}

With the above wording, it is easy to see that there is a global loop variable i.

In addition, all functions should be defined before use. Variable declarations inside the function should be placed at the head of the function.

with statement

with can reduce the writing of the code, but it will cause confusion.

with (o) {
  foo = bar;
}

The above code can have four running results:

o.foo = bar;
o.foo = o.bar;
foo = bar;
foo = o.bar;

These four results may occur, depending on whether the different variables are defined. Therefore, do not use the with statement.

Equality and strict equality

JavaScript has two operators for equality: "equal" (==) and "strictly equal" (===).

The equality operator will automatically convert variable types, causing many unexpected situations.

0 == ""; // true
1 == true; // true
2 == true; // false
0 == "0"; // true
false == "false"; // false
false == "0"; // true
"\t\r\n" == 0; // true

Therefore, it is recommended not to use the equality operator (==), only the strict equality operator (===).

Combination of statements

Some programmers pursue brevity and like to combine statements for different purposes. For example, the original sentence is

a = b;
if (a) {
  // ...
}

He likes to write like this.

if ((a = b)) {
  // ...
}

Although the statement is missing one line, its readability is greatly reduced, and it will cause misunderstandings, allowing others to misunderstand the meaning of this line of code as follows.

if (a === b) {
  // ...
}

It is recommended not to merge statements with different purposes into one line.

Increment and decrement operators

Increment (++) and decrement (--) operators, placed before or after the variable, return different values, which are prone to errors. In fact, all ++ operators can be replaced with += 1.

++x;
// Equivalent to
x += 1;

Use += 1 instead, the code becomes clearer.

It is recommended to use += and -= instead of increment (++) and decrement (--) operators as much as possible.

switch...case structure

The switch...case structure requires that the last line of each case must be a break statement, otherwise the next case will be executed. This is not only easy to forget, it will also cause code verbosity.

Moreover, switch...case does not use curly braces, which is not conducive to the uniformity of the code form. In addition, this structure is similar to the goto statement, which can easily cause confusion in the program flow, making the code structure chaotic and inconsistent with the principles of object-oriented programming.

function doAction(action) {
  switch (action) {
    case "hack":
      return "hack";
    case "slash":
      return "slash";
    case "run":
      return "run";
    default:
      throw new Error("Invalid action.");
  }
}

The above code is recommended to be rewritten into an object structure.

function doAction(action) {
  var actions = {
    hack: function () {
      return "hack";
    },
    slash: function () {
      return "slash";
    },
    run: function () {
      return "run";
    },
  };

  if (typeof actions[action] !== "function") {
    throw new Error("Invalid action.");
  }

  return actions[action]();
}

Therefore, it is recommended that the switch...case structure can be replaced by an object structure.