Programming style
This chapter discusses how to apply ES6's new grammar to coding practice and combine it with traditional JavaScript syntax to write reasonable, easy-to-read and maintain code.
Many companies and organizations have published their style specifications. The following content mainly refers to the JavaScript style specifications of the Airbnb company.
Block-level scope
** (1) let replace var**
ES6 proposes two new commands for declaring variables: let
and const
. Among them, let
can completely replace var
, because the semantics of the two are the same, and let
has no side effects.
strict';
if (true) {
let x ='hello';
}
for (let i = 0; i <10; i++) {
console.log(i);
}
If the above code Substituting var
for let
actually declares two global variables, which is obviously not intended. Variables should only be valid within the code block where they are declared, the var
command cannot do this.
The var
command has variable promotion effect, the let
command does not have this problem.
strict';
if (true) {
console.log(x); // ReferenceError
let x ='hello';
}
If the above code uses var
instead of let
, the line of console.log
will not report an error, but will output undefined
because the variable declaration is promoted to the code block Head. This violates the principle of variable declaration before use.
Therefore, it is recommended not to use the var
command, but to use the let
command instead.
(2) Global constants and thread safety
Between let
and const
, it is recommended to use const
first, especially in the global environment, variables should not be set, only constants should be set.
There are several reasons why const
is better than let
. One is that const
can remind people who read the program that this variable should not be changed; the other is that const
is more in line with the idea of functional programming, the operation does not change the value, just a new value, and this is also conducive to future distributed operations ; The last reason is that the JavaScript compiler optimizes const
, so more use of const
is conducive to improving the running efficiency of the program. That is to say, the essential difference between let
and const
is actually inside the compiler The treatment is different.
// bad
var a = 1,
b = 2,
c = 3;
// good
const a = 1;
const b = 2;
const c = 3;
// best
const [a, b, c] = [1, 2, 3];
There are two other benefits of const
declaration of constants. One is that people who read the code will immediately realize that the value should not be modified, and the other is to prevent errors caused by inadvertently modifying the value of a variable.
All functions should be set to constants.
In the long run, JavaScript may have a multi-threaded implementation (such as Intel’s River Trail projects). At this time, the variables represented by let
should only appear in single-threaded code, not multi-threaded. Shared, which helps to ensure thread safety.
String
Static strings always use single quotes or back quotes, and do not use double quotes. Use backticks for dynamic strings.
// bad
const a = "foobar";
const b = "foo" + a + "bar";
// acceptable
const c = `foobar`;
// good
const a = "foobar";
const b = `foo${a}bar`;
Destructuring assignment
When using array members to assign values to variables, destructuring assignment is preferred.
const arr = [1, 2, 3, 4];
// bad
const first = arr[0];
const second = arr[1];
// good
const [first, second] = arr;
If the parameter of a function is a member of an object, destructuring assignment is preferred.
// bad
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
}
// good
function getFullName(obj) {
const { firstName, lastName } = obj;
}
// best
function getFullName({ firstName, lastName }) {}
If the function returns multiple values, use the destructuring assignment of the object in preference to the destructuring assignment of the array. This makes it easy to add return values later and change the order of return values.
// bad
function processInput(input) {
return [left, right, top, bottom];
}
// good
function processInput(input) {
return { left, right, top, bottom };
}
const { left, right } = processInput(input);
Object A
single-line defined object, the last member does not end with a comma. For objects defined in multiple lines, the last member ends with a comma.
// bad
const a = {k1: v1, k2: v2, };
const b = {
k1: v1,
k2: v2
};
// good
const a = {k1: v1, k2: v2 };
const b = {
k1: v1,
k2: v2,
};
```The
object should be as static as possible. Once defined, no new attributes should be added at will. If adding properties is unavoidable, use the `Object.assign` method.
```javascript
// bad
const a = {};
ax = 3;
// if reshape unavoidable
const a = {};
Object.assign(a, {x: 3 });
// good
const a = {x: null };
ax = 3;
If the attribute name of the object is dynamic, you can use the attribute expression definition when creating the object.
// bad
const obj = {
id: 5,
name:'San Francisco',
};
obj[getKey('enabled')] = true;
// good
const obj = {
id: 5,
name: ' San Francisco',
[getKey('enabled')]: true,
};
```In the
above code, the last attribute name of the object `obj` needs to be calculated. At this time, it is best to use attribute expressions, and define this attribute together with other attributes when creating a new `obj`. In this way, all attributes are defined in one place.
In addition, try to use concise expressions for the attributes and methods of objects, so that they are easy to describe and write.
```javascript
var ref ='some value';
// bad
const atom = {
ref: ref,
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// good
const atom = {
ref,
value: 1,
addValue(value) {
return atom.value + value;
},
};
Array
use spread operator (...) Copy the array.
// bad
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i <len; i++) {
itemsCopy[i] = items[i];
}
// good
const itemsCopy = [...items];
Use the Array.from method to convert an array-like object into an array.
const foo = document.querySelectorAll(".foo");
const nodes = Array.from(foo);
Function The
immediate execution function can be written in the form of an arrow function.
(() => {
console.log("Welcome to the Internet.");
})();
When using anonymous functions as parameters, try to use arrow functions instead. Because it is more concise and binds this.
// bad
[1, 2, 3].map(function (x) {
return x * x;
});
// good
[1, 2, 3].map((x) => {
return x * x;
});
// best
[1, 2, 3].map((x) => x * x);
Arrow function replaces Function.prototype.bind
, self/_this should not be used anymore /that Bind this.
// bad
const self = this;
const boundMethod = function (...params) {
return method.apply(self, params);
};
// acceptable
const boundMethod = method.bind(this);
// best
const boundMethod = (...params) => method.apply(this, params);
Simple, one-line, not reused Function, it is recommended to use arrow functions. If the function body is more complicated and the number of lines is large, the traditional function writing method should be used.
All configuration items should be concentrated in one object and placed in the last parameter. Boolean values cannot be directly used as parameters.
// bad
function divide(a, b, option = false) {
}
// good
function divide(a, b, {option = false} = ()) {
}
Do not use arguments in the function body Variables, use the rest operator (...) instead. Because the rest operator explicitly indicates that you want to get parameters, and arguments is an array-like object, and the rest operator can provide a real array.
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join("");
}
// good
function concatenateAll(...args) {
return args.join("");
}
Use default value syntax to set the default value of function parameters.
// bad
function handleThings(opts) {
opts = opts || {};
}
// good
function handleThings(opts = ()) {
// ...
}
Map structure
pay attention to distinguish Object And Map, only use Object when simulating physical objects in the real world. If you only need the data structure of key: value
, use the Map structure. Because Map has a built-in traversal mechanism.
let map = new Map(arr);
for (let key of map.keys()) {
console.log(key);
}
for (let value of map.values()) {
console.log(value);
}
for (let item of map.entries()) {
console.log(item[0], item[1]);
}
Class
always uses Class instead of operations that require prototype. Because Class is written more concisely and easier to understand.
// bad
function Queue(contents = []) {
this._queue = [...contents];
}
Queue.prototype.pop = function () {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
};
// good
class Queue {
constructor(contents = []) {
this._queue = [...contents];
}
pop() {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
}
Use extends
to implement inheritance, because it is simpler and there is no danger of breaking the operation of instanceof
.
// bad
const inherits = require("inherits");
function PeekableQueue(contents) {
Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
return this._queue[0];
};
// good
class PeekableQueue extends Queue {
peek() {
return this._queue[0];
}
}
Module
First of all, Module syntax is the standard way of writing JavaScript modules, stick to it This way of writing. Use import
instead of require
.
// bad
const moduleA = require("moduleA");
const func1 = moduleA.func1;
const func2 = moduleA.func2;
// good
import { func1, func2 } from "moduleA";
Use export
instead of module.exports
.
// How to write commonJS
var React = require('react');
var Breadcrumbs = React.createClass((
render() {
return <nav />;
}
});
module.exports = Breadcrumbs;
// ES6 wording
Import from React 'REACT';
class {React.Component Breadcrumbs the extends
the render () {
return <NAV />;
}
};
Export default Breadcrumbs;
`` `
If the module has only one output value, use `export default`. If the module has multiple output values, don't use `export default`. Don't use `export default` and ordinary `export` at the same time.
Do not use wildcards in module input. Because this ensures that there is an export default in your module.
```javascript
// bad
import * as myObject from'./importModule';
// good
import myObject from'./importModule';
If the module outputs a function by default, the first letter of the function name should be lowercase.
function makeStyleGuide() {}
export default makeStyleGuide;
If the module outputs an object by default, the first letter of the object name should be capitalized.
const StyleGuide = {
es6: {},
};
export default StyleGuide;
Use of
ESLint ESLint is a tool for checking grammar rules and code styles, which can be used to ensure correct grammar and uniform style Code.
First, install ESLint in the root directory of the project.
$ npm install --save-dev eslint
Then, install Airbnb grammar rules, as well as import, a11y, and react plugins.
$ npm install --save-dev eslint-config-airbnb
$ npm install --save-dev eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react
Finally, in the project Create a new .eslintrc
file in the root directory and configure ESLint.
{
"extends": "eslint-config-airbnb"
}
Now you can check whether the code of the current project complies with the preset rules.
The code of the index.js
file is as follows.
var unused = "I have no purpose!";
function greet() {
var message = "Hello, World!";
console.log(message);
}
greet();
Use ESLint to check this file and it will report an error.
$ npx eslint index.js
index.js
1:1 error Unexpected var, use let or const instead no-var
1:5 error unused is defined but never used no-unused-vars
4:5 error Expected indentation of 2 characters But found. 4 indent
. 4:. 5 error Unexpected var, use the let or const INSTEAD NO-var
. 5:. 5 error the Expected Indentation of 2 characters But found. 4 indent
✖. 5 Problems (. 5 errors, 0 Represents warnings)
`` `
code above described , The original file has five errors, two of which are that the `var` command should not be used, but the use of `let` or `const`; one is that the variable is defined but not used; the other two are that the beginning of the line is indented as 4 spaces instead of the required 2 spaces.