1.不要用遍歷器。用JavaScript高級函數(shù)代替`for-in`、 `for-of`。
const numbers = [1, 2, 3, 4, 5];
? ? // bad
? ? let sum = 0;
? ? for (let num of numbers) {
? ? ? sum += num;
? ? }
? ? sum === 15;
? ? // good
? ? let sum = 0;
? ? numbers.forEach(num => sum += num);
? ? sum === 15;
? ? // best (use the functional force)
? ? const sum = numbers.reduce((total, num) => total + num, 0);
? ? sum === 15;
? ? // bad
? ? const increasedByOne = [];
? ? for (let i = 0; i < numbers.length; i++) {
? ? ? increasedByOne.push(numbers[i] + 1);
? ? }
? ? // good
? ? const increasedByOne = [];
? ? numbers.forEach(num => increasedByOne.push(num + 1));
? ? // best (keeping it functional)
? ? const increasedByOne = numbers.map(num => num + 1);
2不要直接調(diào)用`Object.prototype`上的方法,如`hasOwnProperty`, `propertyIsEnumerable`, `isPrototypeOf`。
// bad
? ? console.log(object.hasOwnProperty(key));
? ? // good
? ? console.log(Object.prototype.hasOwnProperty.call(object, key));
3.對象淺拷貝時,更推薦使用擴(kuò)展運算符[就是`...`運算符],而不是[`Object.assign`]
// bad
? const original = { a: 1, b: 2 };
? const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
? // good es6擴(kuò)展運算符 ...
? const original = { a: 1, b: 2 };
? // 淺拷貝
? const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
? // rest 賦值運算符
? const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
4.用擴(kuò)展運算符做數(shù)組淺拷貝,類似上面的對象淺拷貝
? // bad
? ? const len = items.length;
? ? const itemsCopy = [];
? ? let i;
? ? for (i = 0; i < len; i += 1) {
? ? ? itemsCopy[i] = items[i];
? ? }
? ? // good
? ? const itemsCopy = [...items];
5. 用 `...` 運算符而不是[`Array.from`]
const foo = document.querySelectorAll('.foo');
? ? // good
? ? const nodes = Array.from(foo);
? ? // best
? ? const nodes = [...foo];
6.用對象的解構(gòu)賦值來獲取和使用對象某個或多個屬性值。
// bad
? ? function getFullName(user) {
? ? ? const firstName = user.firstName;
? ? ? const lastName = user.lastName;
? ? ? return `${firstName} ${lastName}`;
? ? }
? ? // good
? ? function getFullName(user) {
? ? ? const { firstName, lastName } = user;
? ? ? return `${firstName} ${lastName}`;
? ? }
? ? // best
? ? function getFullName({ firstName, lastName }) {
? ? ? return `${firstName} ${lastName}`;
? ? }
7. const arr = [1, 2, 3, 4];
? ? // bad
? ? const first = arr[0];
? ? const second = arr[1];
? ? // good
? ? const [first, second] = arr;
8.多個返回值用對象的解構(gòu),而不是數(shù)據(jù)解構(gòu)。
// bad
? ? function processInput(input) {
? ? ? // 然后就是見證奇跡的時刻
? ? ? return [left, right, top, bottom];
? ? }
? ? // 調(diào)用者需要想一想返回值的順序
? ? const [left, __, top] = processInput(input);
? ? // good
? ? function processInput(input) {
? ? ? // oops, 奇跡又發(fā)生了
? ? ? return { left, right, top, bottom };
? ? }
? ? // 調(diào)用者只需要選擇他想用的值就好了
? ? const { left, top } = processInput(input);
9. 用命名函數(shù)表達(dá)式而不是函數(shù)聲明。
// bad
? ? function foo() {
? ? ? // ...
? ? }
? ? // bad
? ? const foo = function () {
? ? ? // ...
? ? };
? ? // good
? ? // lexical name distinguished from the variable-referenced invocation(s)
? ? // 函數(shù)表達(dá)式名和聲明的函數(shù)名是不一樣的
? ? const short = function longUniqueMoreDescriptiveLexicalFoo() {
? ? ? // ...
? ? };
10.不要使用`arguments`,用rest語法`...`代替。
? // bad
? ? function concatenateAll() {
? ? ? const args = Array.prototype.slice.call(arguments);
? ? ? return args.join('');
? ? }
? ? // good
? ? function concatenateAll(...args) {
? ? ? return args.join('');
? ? }
11.用`spread`操作符`...`去調(diào)用多變的函數(shù)更好
? // bad
? ? const x = [1, 2, 3, 4, 5];
? ? console.log.apply(console, x);
? ? // good
? ? const x = [1, 2, 3, 4, 5];
? ? console.log(...x);
? ? // bad
? ? new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));
? ? // good
? ? new Date(...[2016, 8, 5]);
12.當(dāng)你一定要用函數(shù)表達(dá)式(在回調(diào)函數(shù)里)的時候就用箭頭表達(dá)式吧。
// bad
? ? [1, 2, 3].map(function (x) {
? ? ? const y = x + 1;
? ? ? return x * y;
? ? });
? ? // good
? ? [1, 2, 3].map((x) => {
? ? ? const y = x + 1;
? ? ? return x * y;
? ? });
13.常用`class`,避免直接操作`prototype`
// 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;
? ? ? }
? ? }
14. 用`extends`實現(xiàn)繼承
? // 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];
? ? ? }
? ? }
15.可以返回`this`來實現(xiàn)方法鏈
? // bad
? ? Jedi.prototype.jump = function () {
? ? ? this.jumping = true;
? ? ? return true;
? ? };
? ? Jedi.prototype.setHeight = function (height) {
? ? ? this.height = height;
? ? };
? ? const luke = new Jedi();
? ? luke.jump(); // => true
? ? luke.setHeight(20); // => undefined
? ? // good
? ? class Jedi {
? ? ? jump() {
? ? ? ? this.jumping = true;
? ? ? ? return this;
? ? ? }
? ? ? setHeight(height) {
? ? ? ? this.height = height;
? ? ? ? return this;
? ? ? }
? ? }
? ? const luke = new Jedi();
? ? luke.jump()
? ? ? .setHeight(20);
16.如果沒有具體說明,類有默認(rèn)的構(gòu)造方法。一個空的構(gòu)造函數(shù)或只是代表父類的構(gòu)造函數(shù)是不需要寫的。
// bad
? ? class Jedi {
? ? ? constructor() {}
? ? ? getName() {
? ? ? ? return this.name;
? ? ? }
? ? }
? ? // bad
? ? class Rey extends Jedi {
? ? ? // 這種構(gòu)造函數(shù)是不需要寫的
? ? ? constructor(...args) {
? ? ? ? super(...args);
? ? ? }
? ? }
? ? // good
? ? class Rey extends Jedi {
? ? ? constructor(...args) {
? ? ? ? super(...args);
? ? ? ? this.name = 'Rey';
? ? ? }
? ? }
17. 一個路徑只 import 一次。
// bad
? ? import foo from 'foo';
? ? // … some other imports … //
? ? import { named1, named2 } from 'foo';
? ? // good
? ? import foo, { named1, named2 } from 'foo';
? ? // good
? ? import foo, {
? ? ? named1,
? ? ? named2,
? ? } from 'foo';
18. 做冪運算時用冪操作符 `**` 。
? // bad
? ? const binary = Math.pow(2, 10);
? ? // good
? ? const binary = 2 ** 10;
19.三元表達(dá)式不應(yīng)該嵌套,通常是單行表達(dá)式。
? // bad
? ? const foo = maybe1 > maybe2
? ? ? ? "bar"
? ? ? : value1 > value2 ? "baz" : null;
? ? // better
? ? const maybeNull = value1 > value2 ? 'baz' : null;
? ? const foo = maybe1 > maybe2
? ? ? ? 'bar'
? ? ? : maybeNull;
? ? // best
? ? const maybeNull = value1 > value2 ? 'baz' : null;
? ? const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
20.避免不需要的三元表達(dá)式
? // bad
? ? const foo = a ? a : b;
? ? const bar = c ? true : false;
? ? const baz = c ? false : true;
? ? // good
? ? const foo = a || b;
? ? const bar = !!c;
? ? const baz = !c;
21. 如果 `if` 語句中總是需要用 `return` 返回, 那后續(xù)的 `else` 就不需要寫了。 `if` 塊中包含 `return`, 它后面的 `else if` 塊中也包含了 `return`, 這個時候就可以把 `return` 分到多個 `if` 語句塊中。
? // bad
? ? function foo() {
? ? ? if (x) {
? ? ? ? return x;
? ? ? } else {
? ? ? ? return y;
? ? ? }
? ? }
? ? // bad
? ? function cats() {
? ? ? if (x) {
? ? ? ? return x;
? ? ? } else if (y) {
? ? ? ? return y;
? ? ? }
? ? }
? ? // bad
? ? function dogs() {
? ? ? if (x) {
? ? ? ? return x;
? ? ? } else {
? ? ? ? if (y) {
? ? ? ? ? return y;
? ? ? ? }
? ? ? }
? ? }
? ? // good
? ? function foo() {
? ? ? if (x) {
? ? ? ? return x;
? ? ? }
? ? ? return y;
? ? }
? ? // good
? ? function cats() {
? ? ? if (x) {
? ? ? ? return x;
? ? ? }
? ? ? if (y) {
? ? ? ? return y;
? ? ? }
? ? }
? ? // good
? ? function dogs(x) {
? ? ? if (x) {
? ? ? ? if (z) {
? ? ? ? ? return y;
? ? ? ? }
? ? ? } else {
? ? ? ? return z;
? ? ? }
? ? }
摘自https://github.com/airbnb/javascript.git