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.