{"id":15020722,"url":"https://github.com/lin-123/javascript","last_synced_at":"2025-10-01T12:30:47.896Z","repository":{"id":39833413,"uuid":"79328751","full_name":"lin-123/javascript","owner":"lin-123","description":"eslint-config-airbnb 中文版","archived":false,"fork":true,"pushed_at":"2024-05-06T07:07:07.000Z","size":4315,"stargazers_count":2014,"open_issues_count":1,"forks_count":438,"subscribers_count":27,"default_branch":"cn","last_synced_at":"2024-09-25T04:33:26.094Z","etag":null,"topics":["airbnb","chinese-translation","eslint"],"latest_commit_sha":null,"homepage":"https://lin-123.github.io/javascript/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"airbnb/javascript","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lin-123.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-18T10:21:23.000Z","updated_at":"2024-09-25T01:50:58.000Z","dependencies_parsed_at":"2023-02-19T15:45:31.993Z","dependency_job_id":null,"html_url":"https://github.com/lin-123/javascript","commit_stats":null,"previous_names":[],"tags_count":85,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lin-123%2Fjavascript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lin-123%2Fjavascript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lin-123%2Fjavascript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lin-123%2Fjavascript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lin-123","download_url":"https://codeload.github.com/lin-123/javascript/tar.gz/refs/heads/cn","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219875422,"owners_count":16554677,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["airbnb","chinese-translation","eslint"],"created_at":"2024-09-24T19:55:29.788Z","updated_at":"2025-10-01T12:30:47.545Z","avatar_url":"https://github.com/lin-123.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Airbnb JavaScript 风格指南() {\n\n*使用 JavaScript 最合理的方式*。\n\n\u003e **注意**: 这个指南假定你正在使用 [Babel](https://babeljs.io)，并且需要你使用 [babel-preset-airbnb](https://npmjs.com/babel-preset-airbnb) 或与其等效的预设。同时假定你在你的应用里安装了 带有 [airbnb-browser-shims](https://npmjs.com/airbnb-browser-shims) 或与其等效的插件的 `shims/polyfills`。\n\n[![Downloads](https://img.shields.io/npm/dm/eslint-config-airbnb.svg)](https://www.npmjs.com/package/eslint-config-airbnb)\n[![Downloads](https://img.shields.io/npm/dm/eslint-config-airbnb-base.svg)](https://www.npmjs.com/package/eslint-config-airbnb-base)\n[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge)\n\n这个指南支持的其他语言翻译版请看 [Translation](#translation)。\n\n其他风格指南：\n - [ES5 (已废弃)](https://github.com/airbnb/javascript/tree/es5-deprecated/es5)\n - [React](react/)\n - [CSS-in-JavaScript](css-in-javascript/)\n - [CSS \u0026 Sass](https://github.com/airbnb/css)\n - [Ruby](https://github.com/airbnb/ruby)\n\n## 目录\n\n- [Airbnb JavaScript 风格指南() {](#airbnb-javascript-风格指南-)\n  - [目录](#目录)\n  - [类型](#类型)\n  - [引用](#引用)\n  - [对象](#对象)\n  - [数组](#数组)\n  - [解构](#解构)\n  - [字符串](#字符串)\n  - [函数](#函数)\n  - [箭头函数](#箭头函数)\n  - [类与构造函数](#类与构造函数)\n  - [模块](#模块)\n  - [迭代器与生成器](#迭代器与生成器)\n  - [属性](#属性)\n  - [变量](#变量)\n  - [提升](#提升)\n  - [比较运算符与相等](#比较运算符与相等)\n  - [块](#块)\n  - [控制语句](#控制语句)\n  - [注释](#注释)\n  - [空格](#空格)\n  - [逗号](#逗号)\n  - [分号](#分号)\n  - [类型转换与强制转换](#类型转换与强制转换)\n  - [命名规范](#命名规范)\n  - [Get-Set 访问器](#get-set-访问器)\n  - [事件](#事件)\n  - [jQuery](#jquery)\n  - [ECMAScript 5 兼容性](#ecmascript-5-兼容性)\n  - [ECMAScript 6+ (ES 2015+) 风格](#ecmascript-6-es-2015-风格)\n  - [标准库](#标准库)\n  - [测试](#测试)\n  - [性能](#性能)\n  - [资源](#资源)\n  - [In the Wild](#in-the-wild)\n  - [Translation](#translation)\n  - [The JavaScript Style Guide Guide](#the-javascript-style-guide-guide)\n  - [Chat With Us About JavaScript](#chat-with-us-about-javascript)\n  - [Contributors](#contributors)\n  - [License](#license)\n  - [Amendments](#amendments)\n- [};](#)\n\n## 类型\n\n  \u003ca name=\"1.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"types--primitives\"\u003e\u003c/a\u003e\n\n  - [1.1](#types--primitives) 基本类型: 你可以直接获取到基本类型的值\n\n    + `string`\n    + `number`\n    + `boolean`\n    + `null`\n    + `undefined`\n    + `symbol`\n    + `bigint`\n\n    ```javascript\n    const foo = 1;\n    let bar = foo;\n\n    bar = 9;\n\n    console.log(foo, bar); // =\u003e 1, 9\n    ```\n    + 由于 Symbols 和 BigInts 不能被正确的 polyfill。所以不应在不能原生支持这些类型的环境或浏览器中使用他们。\n\n  \u003ca name=\"1.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"types--complex\"\u003e\u003c/a\u003e\n\n  - [1.2](#types--complex)  复杂类型: 复杂类型赋值是获取到他的引用的值。\n\n    + `object`\n    + `array`\n    + `function`\n\n    ```javascript\n    const foo = [1, 2];\n    const bar = foo;\n\n    bar[0] = 9;\n\n    console.log(foo[0], bar[0]); // =\u003e 9, 9\n    ```\n\n**[⬆ 回到顶部](#目录)**\n\n## 引用\n\n  \u003ca name=\"2.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"references--prefer-const\"\u003e\u003c/a\u003e\n\n  - [2.1](#references--prefer-const) 所有的赋值都用 `const`，避免使用 `var`。eslint: [`prefer-const`](http://eslint.org/docs/rules/prefer-const), [`no-const-assign`](http://eslint.org/docs/rules/no-const-assign)\n\n    \u003e 为什么？因为这个能确保你不会改变你的初始值，重复引用会导致 bug 并且使代码变得难以理解。\n\n    ```javascript\n    // bad\n    var a = 1;\n    var b = 2;\n\n    // good\n    const a = 1;\n    const b = 2;\n    ```\n\n  \u003ca name=\"2.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"references--disallow-var\"\u003e\u003c/a\u003e\n\n  - [2.2](#references--disallow-var) 如果你一定要对参数重新赋值，使用 `let`，而不是 `var`。eslint: [`no-var`](http://eslint.org/docs/rules/no-var)\n\n    \u003e 为什么？因为 `let` 是块级作用域，而 `var` 是函数级作用域。\n\n    ```javascript\n    // bad\n    var count = 1;\n    if (true) {\n      count += 1;\n    }\n\n    // good, use the let.\n    let count = 1;\n    if (true) {\n      count += 1;\n    }\n    ```\n\n  \u003ca name=\"2.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"references--block-scope\"\u003e\u003c/a\u003e\n  - [2.3](#references--block-scope) 注意：`let` 和 `const` 都是块级作用域， 而 `var` 是函数级作用域\n\n    ```javascript\n    // const 和 let 都只存在于它被定义的那个块级作用域。\n    {\n      let a = 1;\n      const b = 1;\n      var c = 1;\n    }\n    console.log(a); // 引用错误\n    console.log(b); // 引用错误\n    console.log(c); // 打印 1\n    ```\n\n    上面的代码里，`a` 和 `b` 的定义会报引用错误，这是因为 `a` 和 `b` 是块级作用域， 而 `c` 的作用域是在函数里的。\n\n**[⬆ 返回顶部](#目录)**\n\n## 对象\n\n  \u003ca name=\"3.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"objects--no-new\"\u003e\u003c/a\u003e\n  - [3.1](#objects--no-new) 使用字面值创建对象。eslint: [`no-new-object`](http://eslint.org/docs/rules/no-new-object)\n\n    ```javascript\n    // bad\n    const item = new Object();\n\n    // good\n    const item = {};\n    ```\n\n  \u003ca name=\"3.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"es6-computed-properties\"\u003e\u003c/a\u003e\n\n  - [3.2](#es6-computed-properties) 使用计算属性名创建一个带有动态属性名的对象。\n\n    \u003e 为什么？因为这可以使你在同一个地方定义所有对象属性。\n\n    ```javascript\n\n    function getKey(k) {\n      return `a key named ${k}`;\n    }\n\n    // bad\n    const obj = {\n      id: 5,\n      name: 'San Francisco',\n    };\n    obj[getKey('enabled')] = true;\n\n    // good\n    const obj = {\n      id: 5,\n      name: 'San Francisco',\n      [getKey('enabled')]: true,\n    };\n    ```\n\n  \u003ca name=\"3.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"es6-object-shorthand\"\u003e\u003c/a\u003e\n\n  - [3.3](#es6-object-shorthand) 用对象方法简写。eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand)\n\n    ```javascript\n    // bad\n    const atom = {\n      value: 1,\n\n      addValue: function (value) {\n        return atom.value + value;\n      },\n    };\n\n    // good\n    const atom = {\n      value: 1,\n\n      // 对象的方法\n      addValue(value) {\n        return atom.value + value;\n      },\n    };\n    ```\n\n  \u003ca name=\"3.4\"\u003e\u003c/a\u003e\n  \u003ca name=\"es6-object-concise\"\u003e\u003c/a\u003e\n  - [3.4](#es6-object-concise) 用属性值缩写。eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand)\n\n    \u003e 为什么？这样写更简洁，且可读性更高。\n\n    ```javascript\n    const lukeSkywalker = 'Luke Skywalker';\n\n    // bad\n    const obj = {\n      lukeSkywalker: lukeSkywalker,\n    };\n\n    // good\n    const obj = {\n      lukeSkywalker,\n    };\n    ```\n\n  \u003ca name=\"3.5\"\u003e\u003c/a\u003e\n  \u003ca name=\"objects--grouped-shorthand\"\u003e\u003c/a\u003e\n\n  - [3.5](#objects--grouped-shorthand) 将你的所有缩写放在对象声明的前面。\n\n    \u003e 为什么？因为这样能更方便地知道有哪些属性用了缩写。\n\n    ```javascript\n    const anakinSkywalker = 'Anakin Skywalker';\n    const lukeSkywalker = 'Luke Skywalker';\n\n    // bad\n    const obj = {\n      episodeOne: 1,\n      twoJediWalkIntoACantina: 2,\n      lukeSkywalker,\n      episodeThree: 3,\n      mayTheFourth: 4,\n      anakinSkywalker,\n    };\n\n    // good\n    const obj = {\n      lukeSkywalker,\n      anakinSkywalker,\n      episodeOne: 1,\n      twoJediWalkIntoACantina: 2,\n      episodeThree: 3,\n      mayTheFourth: 4,\n    };\n    ```\n\n  \u003ca name=\"3.6\"\u003e\u003c/a\u003e\n  \u003ca name=\"objects--quoted-props\"\u003e\u003c/a\u003e\n\n  - [3.6](#objects--quoted-props) 只对那些无效的标示使用引号 `''`。eslint: [`quote-props`](http://eslint.org/docs/rules/quote-props)\n\n    \u003e 为什么？通常我们认为这种方式主观上更易读。不仅优化了代码高亮，而且也更容易被许多 JS 引擎优化。\n\n    ```javascript\n    // bad\n    const bad = {\n      'foo': 3,\n      'bar': 4,\n      'data-blah': 5,\n    };\n\n    // good\n    const good = {\n      foo: 3,\n      bar: 4,\n      'data-blah': 5,\n    };\n    ```\n\n  \u003ca name=\"3.7\"\u003e\u003c/a\u003e\n  \u003ca name=\"objects--prototype-builtins\"\u003e\u003c/a\u003e\n  - [3.7](#objects--prototype-builtins) 不要直接调用 `Object.prototype`上的方法，如 `hasOwnProperty`、`propertyIsEnumerable`、`isPrototypeOf`。eslint: [`no-prototype-builtins`](htt\nps://eslint.org/docs/rules/no-prototype-builtins)\n\n    \u003e 为什么？在一些有问题的对象上，这些方法可能会被屏蔽掉，如：`{ hasOwnProperty: false }` 或空对象 `Object.create(null)`。 在支持 ES2022 的现代浏览器中，或者被做过类似 \u003chttps://npmjs.com/object.hasown\u003e 的兼容情况下， `Object.hasOwn` 也会被用作 `Object.prototype.hasOwnProperty.call` 的替代品。\n\n    ```javascript\n    // bad\n    console.log(object.hasOwnProperty(key));\n\n    // good\n    console.log(Object.prototype.hasOwnProperty.call(object, key));\n\n    // better\n    const has = Object.prototype.hasOwnProperty; // 在模块作用域内做一次缓存。\n    console.log(has.call(object, key));\n\n    // best\n    console.log(Object.hasOwn(object, key)); // 只能在支持 ES2022 的浏览器中使用\n\n    /* or */\n    import has from 'has'; // https://www.npmjs.com/package/has\n    console.log(has(object, key));\n    /* or */\n    console.log(Object.hasOwn(object, key)); // https://www.npmjs.com/package/object.hasown\n    ```\n\n  \u003ca name=\"3.8\"\u003e\u003c/a\u003e\n  \u003ca name=\"objects--rest-spread\"\u003e\u003c/a\u003e\n\n  - [3.8](#objects--rest-spread) 对象浅拷贝时，更推荐使用扩展运算符（即 `...` 运算符），而不是 [`Object.assign`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)。获取对象指定的几个属性时，用对象的 rest 解构运算符（即 `...` 运算符）更好。eslint: [`prefer-object-spread`](https://eslint.org/docs/rules/prefer-object-spread)\n    + 这一段不太好翻译出来， 大家看下面的例子就懂了。^.^\n\n  ```javascript\n  // very bad\n  const original = { a: 1, b: 2 };\n  const copy = Object.assign(original, { c: 3 }); // 改了 `original` ಠ_ಠ\n  delete copy.a; // so does this\n\n  // bad\n  const original = { a: 1, b: 2 };\n  const copy = Object.assign({}, original, { c: 3 }); // copy =\u003e { a: 1, b: 2, c: 3 }\n\n  // good es6 扩展运算符 ...\n  const original = { a: 1, b: 2 };\n  // 浅拷贝\n  const copy = { ...original, c: 3 }; // copy =\u003e { a: 1, b: 2, c: 3 }\n\n  // rest 解构运算符\n  const { a, ...noA } = copy; // noA =\u003e { b: 2, c: 3 }\n  ```\n\n**[⬆ 返回顶部](#目录)**\n\n## 数组\n\n  \u003ca name=\"4.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"arrays--literals\"\u003e\u003c/a\u003e\n\n  - [4.1](#arrays--literals) 用字面量创建数组。eslint: [`no-array-constructor`](http://eslint.org/docs/rules/no-array-constructor)\n\n    ```javascript\n    // bad\n    const items = new Array();\n\n    // good\n    const items = [];\n    ```\n\n  \u003ca name=\"4.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"arrays--push\"\u003e\u003c/a\u003e\n  - [4.2](#arrays--push) 用 [Array#push](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/push) 代替直接向数组中添加一个值。\n\n    ```javascript\n    const someStack = [];\n\n    // bad\n    someStack[someStack.length] = 'abracadabra';\n\n    // good\n    someStack.push('abracadabra');\n    ```\n\n  \u003ca name=\"4.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"es6-array-spreads\"\u003e\u003c/a\u003e\n  - [4.3](#es6-array-spreads) 用扩展运算符做数组浅拷贝，类似上面的对象浅拷贝。\n\n    ```javascript\n    // bad\n    const len = items.length;\n    const itemsCopy = [];\n    let i;\n\n    for (i = 0; i \u003c len; i += 1) {\n      itemsCopy[i] = items[i];\n    }\n\n    // good\n    const itemsCopy = [...items];\n    ```\n\n  \u003ca name=\"arrays--from\"\u003e\u003c/a\u003e\n  \u003ca name=\"arrays--from-iterable\"\u003e\u003c/a\u003e\u003ca name=\"4.4\"\u003e\u003c/a\u003e\n\n  - [4.4](#arrays--from-iterable) 用 `...` 运算符而不是 [`Array.from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from) 来将一个可迭代的对象转换成数组。\n\n    ```javascript\n    const foo = document.querySelectorAll('.foo');\n\n    // good\n    const nodes = Array.from(foo);\n\n    // best\n    const nodes = [...foo];\n    ```\n\n  \u003ca name=\"arrays--from-array-like\"\u003e\u003c/a\u003e\n  - [4.5](#arrays--from-array-like) 用 [`Array.from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from) 将一个类数组对象转成一个数组。\n\n    ```javascript\n    const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 };\n\n    // bad\n    const arr = Array.prototype.slice.call(arrLike);\n\n    // good\n    const arr = Array.from(arrLike);\n    ```\n\n  \u003ca name=\"4.6\"\u003e\u003c/a\u003e\n  \u003ca name=\"arrays--mapping\"\u003e\u003c/a\u003e\n\n  - [4.6](#arrays--mapping) 用 [`Array.from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from) 而不是 `...` 运算符去做 map 遍历。 因为这样可以避免创建一个临时数组。\n\n    ```javascript\n    // bad\n    const baz = [...foo].map(bar);\n\n    // good\n    const baz = Array.from(foo, bar);\n    ```\n\n  \u003ca name=\"4.7\"\u003e\u003c/a\u003e\n  \u003ca name=\"arrays--callback-return\"\u003e\u003c/a\u003e\n\n  - [4.7](#arrays--callback-return) 在数组方法的回调函数中使用 return 语句。如果函数体由一条返回一个表达式的语句组成，并且这个表达式没有副作用， 这个时候可以忽略 return，详见 [8.2](#arrows--implicit-return)。eslint: [`array-callback-return`](http://eslint.org/docs/rules/array-callback-return)\n\n    ```javascript\n    // good\n    [1, 2, 3].map((x) =\u003e {\n      const y = x + 1;\n      return x * y;\n    });\n\n    // good 函数只有一个语句\n    [1, 2, 3].map((x) =\u003e x + 1);\n\n    // bad - 没有返回值， 因为在第一次迭代后 acc 就变成 undefined 了\n    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) =\u003e {\n      const flatten = acc.concat(item);\n    });\n\n    // good\n    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) =\u003e {\n      const flatten = acc.concat(item);\n      return flatten;\n    });\n\n    // bad\n    inbox.filter((msg) =\u003e {\n      const { subject, author } = msg;\n      if (subject === 'Mockingbird') {\n        return author === 'Harper Lee';\n      } else {\n        return false;\n      }\n    });\n\n    // good\n    inbox.filter((msg) =\u003e {\n      const { subject, author } = msg;\n      if (subject === 'Mockingbird') {\n        return author === 'Harper Lee';\n      }\n\n      return false;\n    });\n    ```\n\n  \u003ca name=\"4.8\"\u003e\u003c/a\u003e\n  \u003ca name=\"arrays--bracket-newline\"\u003e\u003c/a\u003e\n  - [4.8](#arrays--bracket-newline) 如果一个数组有很多行，在数组的 `[` 后和 `]` 前断行。请看下面示例：\n\n    ```javascript\n    // bad\n    const arr = [\n      [0, 1], [2, 3], [4, 5],\n    ];\n\n    const objectInArray = [{\n      id: 1,\n    }, {\n      id: 2,\n    }];\n\n    const numberInArray = [\n      1, 2,\n    ];\n\n    // good\n    const arr = [[0, 1], [2, 3], [4, 5]];\n\n    const objectInArray = [\n      {\n        id: 1,\n      },\n      {\n        id: 2,\n      },\n    ];\n\n    const numberInArray = [\n      1,\n      2,\n    ];\n    ```\n\n**[⬆ 返回顶部](#目录)**\n\n## 解构\n\n  \u003ca name=\"5.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"destructuring--object\"\u003e\u003c/a\u003e\n  - [5.1](#destructuring--object) 用对象的解构赋值来获取和使用对象某个或多个属性值。eslint: [`prefer-destructuring`](https://eslint.org/docs/rules/prefer-destructuring)\n\n    \u003e 为什么？ 解构使您不必为这些属性创建临时引用，并且避免重复引用对象。重复引用对象将造成代码重复、增加阅读次数、提高犯错概率。在一个块级作用域里，解构对象可以在同一个地方给解构字段赋值，而不需要读整个的代码块看它到底用了哪些字段。\n\n    ```javascript\n    // bad\n    function getFullName(user) {\n      const firstName = user.firstName;\n      const lastName = user.lastName;\n\n      return `${firstName} ${lastName}`;\n    }\n\n    // good\n    function getFullName(user) {\n      const { firstName, lastName } = user;\n      return `${firstName} ${lastName}`;\n    }\n\n    // best\n    function getFullName({ firstName, lastName }) {\n      return `${firstName} ${lastName}`;\n    }\n    ```\n\n  \u003ca name=\"5.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"destructuring--array\"\u003e\u003c/a\u003e\n\n  - [5.2](#destructuring--array) 用数组解构。eslint: [`prefer-destructuring`](https://eslint.org/docs/rules/prefer-destructuring)\n\n    ```javascript\n    const arr = [1, 2, 3, 4];\n\n    // bad\n    const first = arr[0];\n    const second = arr[1];\n\n    // good\n    const [first, second] = arr;\n    ```\n\n  \u003ca name=\"5.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"destructuring--object-over-array\"\u003e\u003c/a\u003e\n  - [5.3](#destructuring--object-over-array) 多个返回值用对象的解构，而不是数组解构。\n\n    \u003e 为什么？你可以在后期添加新的属性或者变换变量的顺序而不会破坏原有的引用。\n\n    ```javascript\n    // bad\n    function processInput(input) {\n      // 然后就是见证奇迹的时刻\n      return [left, right, top, bottom];\n    }\n\n    // 调用者需要想一想返回值的顺序\n    const [left, __, top] = processInput(input);\n\n    // good\n    function processInput(input) {\n      // oops，奇迹又发生了\n      return { left, right, top, bottom };\n    }\n\n    // 调用者只需要选择他想用的值就好了\n    const { left, top } = processInput(input);\n    ```\n\n**[⬆ back to top](#目录)**\n\n## 字符串\n\n  \u003ca name=\"6.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"strings--quotes\"\u003e\u003c/a\u003e\n  - [6.1](#strings--quotes) 字符串应使用单引号 `''` 。eslint: [`quotes`](https://eslint.org/docs/rules/quotes)\n\n    ```javascript\n    // bad\n    const name = \"Capt. Janeway\";\n\n    // bad - 模板字符串应该包含插入文字或换行\n    const name = `Capt. Janeway`;\n\n    // good\n    const name = 'Capt. Janeway';\n    ```\n\n  \u003ca name=\"6.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"strings--line-length\"\u003e\u003c/a\u003e\n\n  - [6.2](#strings--line-length) 超过 100 个字符的字符串不应该用字符串连接成多行。\n\n    \u003e 为什么？字符串折行增加编写难度且不易被搜索。\n\n    ```javascript\n    // bad\n    const errorMessage = 'This is a super long error that was thrown because \\\n        of Batman. When you stop to think about how Batman had anything to do \\\n        with this, you would get nowhere \\\n    fast.';\n\n    // bad\n    const errorMessage = 'This is a super long error that was thrown because ' +\n        'of Batman. When you stop to think about how Batman had anything to do ' +\n    'with this, you would get nowhere fast.';\n\n    // good\n    const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';\n    ```\n\n  \u003ca name=\"6.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"es6-template-literals\"\u003e\u003c/a\u003e\n  - [6.3](#es6-template-literals) 当需要动态生成字符串时，使用模板字符串而不是字符串拼接。eslint: [`prefer-template`](https://eslint.org/docs/rules/prefer-template) [`template-curly-spacing`](https://eslint.org/docs/rules/template-curly-spacing)\n\n    \u003e 为什么？模板字符串更具可读性、多行语法更简洁以及更方便插入变量到字符串里头。\n\n    ```javascript\n    // bad\n    function sayHi(name) {\n      return 'How are you, ' + name + '?';\n    }\n\n    // bad\n    function sayHi(name) {\n      return ['How are you, ', name, '?'].join();\n    }\n\n    // bad\n    function sayHi(name) {\n      return `How are you, ${ name }?`;\n    }\n\n    // good\n    function sayHi(name) {\n      return `How are you, ${name}?`;\n    }\n    ```\n\n  \u003ca name=\"6.4\"\u003e\u003c/a\u003e\n  \u003ca name=\"strings--eval\"\u003e\u003c/a\u003e\n\n  - [6.4](#strings--eval) 永远不要使用 `eval()`，该方法有太多漏洞。eslint: [`no-eval`](https://eslint.org/docs/rules/no-eval)\n\n  \u003ca name=\"6.5\"\u003e\u003c/a\u003e\n  \u003ca name=\"strings--escaping\"\u003e\u003c/a\u003e\n\n  - [6.5](#strings--escaping) 不要使用不必要的转义字符。eslint: [`no-useless-escape`](http://eslint.org/docs/rules/no-useless-escape)\n\n    \u003e 为什么？反斜线可读性差，因此仅当必要时才使用它。\n\n    ```javascript\n    // bad\n    const foo = '\\'this\\' \\i\\s \\\"quoted\\\"';\n\n    // good\n    const foo = '\\'this\\' is \"quoted\"';\n\n    //best\n    const foo = `my name is '${name}'`;\n    ```\n\n**[⬆ 返回顶部](#目录)**\n\n\n## 函数\n\n  \u003ca name=\"7.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"functions--declarations\"\u003e\u003c/a\u003e\n\n  - [7.1](#functions--declarations) 使用命名函数表达式而不是函数声明。eslint: [`func-style`](http://eslint.org/docs/rules/func-style) [`func-names`](https://eslint.org/docs/latest/rules/func-names)\n\n    \u003e 函数表达式： const func = function () {}\n\n    \u003e 函数声明： function func() {}\n\n    \u003e 为什么？函数声明会发生提升，这意味着在一个文件里函数很容易在其被定义之前就被引用了。这样伤害了代码可读性和可维护性。如果你发现一个函数又大又复杂，且这个函数妨碍了这个文件其他部分的理解性，你应当单独把这个函数提取成一个单独的模块。不管这个名字是不是由一个确定的变量推断出来的，别忘了给表达式清晰的命名（这在现代浏览器和类似 babel 编译器中很常见）。这消除了由匿名函数在错误调用栈产生的所有假设。 ([讨论](https://github.com/airbnb/javascript/issues/794))\n\n      \u003e 译者注：这一段可能不是很好理解，简单来说就是使用函数声明会发生提升（即在函数被声明之前就可以使用）；使用匿名函数会导致报错难以定位错误。[常见错误范例](https://github.com/lin-123/javascript/issues/26) [这一段英文原文在这](https://github.com/airbnb/javascript#functions)。\n\n    ```javascript\n    // bad\n    function foo() {\n      // ...\n    }\n\n    // bad\n    const foo = function () {\n      // ...\n    };\n\n    // good\n    // lexical name distinguished from the variable-referenced invocation(s)\n    // 函数表达式名和声明的函数名是不一样的\n    const short = function longUniqueMoreDescriptiveLexicalFoo() {\n      // ...\n    };\n    ```\n\n  \u003ca name=\"7.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"functions--iife\"\u003e\u003c/a\u003e\n  - [7.2](#functions--iife) 把立即执行函数包裹在圆括号里。eslint: [`wrap-iife`](http://eslint.org/docs/rules/wrap-iife)\n\n    \u003e 立即执行函数：Immediately Invoked Function expression = IIFE。\n    \u003e 为什么？一个立即调用的函数表达式是一个单元 - 把它和它的调用者（圆括号）包裹起来，使代码读起来更清晰。\n    \u003e 另外，在模块化世界里，你几乎用不着 IIFE。\n\n    ```javascript\n    // immediately-invoked function expression (IIFE)\n    (function () {\n      console.log('Welcome to the Internet. Please follow me.');\n    }());\n    ```\n\n  \u003ca name=\"7.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"functions--in-blocks\"\u003e\u003c/a\u003e\n\n  - [7.3](#functions--in-blocks) 不要在非函数块（`if`、`while` 等）内声明函数。把这个函数分配给一个变量。浏览器会允许你这样做，但不同浏览器的解析方式不同，这是一个坏消息。eslint: [`no-loop-func`](http://eslint.org/docs/rules/no-loop-func)\n\n  \u003ca name=\"7.4\"\u003e\u003c/a\u003e\n  \u003ca name=\"functions--note-on-blocks\"\u003e\u003c/a\u003e\n\n  - [7.4](#functions--note-on-blocks) **注意**：ECMA-262 中对块（`block`）的定义是： 一系列的语句。但是函数声明不是一个语句， 函数表达式是一个语句。\n\n    ```javascript\n    // bad\n    if (currentUser) {\n      function test() {\n        console.log('Nope.');\n      }\n    }\n\n    // good\n    let test;\n    if (currentUser) {\n      test = () =\u003e {\n        console.log('Yup.');\n      };\n    }\n    ```\n\n  \u003ca name=\"7.5\"\u003e\u003c/a\u003e\n  \u003ca name=\"functions--arguments-shadow\"\u003e\u003c/a\u003e\n  - [7.5](#functions--arguments-shadow) 不要用 `arguments` 命名参数。他的优先级高于每个函数作用域自带的 `arguments` 对象，这会导致函数自带的 `arguments` 值被覆盖。\n\n    ```javascript\n    // bad\n    function foo(name, options, arguments) {\n      // ...\n    }\n\n    // good\n    function foo(name, options, args) {\n      // ...\n    }\n    ```\n\n  \u003ca name=\"7.6\"\u003e\u003c/a\u003e\n  \u003ca name=\"es6-rest\"\u003e\u003c/a\u003e\n\n  - [7.6](#es6-rest) 不要使用 `arguments`，用收集参数语法 `...` 代替。eslint: [`prefer-rest-params`](http://eslint.org/docs/rules/prefer-rest-params)\n\n    \u003e 为什么？`...` 明确你想用哪个参数。而且收集参数是真数组，而不是类似数组的 `arguments`。\n\n    ```javascript\n    // bad\n    function concatenateAll() {\n      const args = Array.prototype.slice.call(arguments);\n      return args.join('');\n    }\n\n    // good\n    function concatenateAll(...args) {\n      return args.join('');\n    }\n    ```\n\n  \u003ca name=\"7.7\"\u003e\u003c/a\u003e\n  \u003ca name=\"es6-default-parameters\"\u003e\u003c/a\u003e\n\n  - [7.7](#es6-default-parameters) 用默认参数语法而不是在函数里对参数重新赋值。\n\n    ```javascript\n    // really bad\n    function handleThings(opts) {\n      // 不！我们不该修改 arguments\n      // 第二：如果 opts 的值为 false, 它会被赋值为 {}\n      // 虽然你想这么写，但是这个会带来一些微妙的 bug。\n      opts = opts || {};\n      // ...\n    }\n\n    // still bad\n    function handleThings(opts) {\n      if (opts === void 0) {\n        opts = {};\n      }\n      // ...\n    }\n\n    // good\n    function handleThings(opts = {}) {\n      // ...\n    }\n    ```\n\n  \u003ca name=\"7.8\"\u003e\u003c/a\u003e\n  \u003ca name=\"functions--default-side-effects\"\u003e\u003c/a\u003e\n\n  - [7.8](#functions--default-side-effects) 避免默认参数的副作用。\n\n    \u003e 为什么？他会令人迷惑不解，比如下面这个，a 到底等于几，这个需要想一下。\n\n    ```javascript\n    var b = 1;\n    // bad\n    function count(a = b++) {\n      console.log(a);\n    }\n    count();  // 1\n    count();  // 2\n    count(3); // 3\n    count();  // 3\n    ```\n\n  \u003ca name=\"7.9\"\u003e\u003c/a\u003e\n  \u003ca name=\"functions--defaults-last\"\u003e\u003c/a\u003e\n  - [7.9](#functions--defaults-last) 把默认参数赋值放在最后。eslint: [`default-param-last`](https://eslint.org/docs/rules/default-param-last)\n\n    ```javascript\n    // bad\n    function handleThings(opts = {}, name) {\n      // ...\n    }\n\n    // good\n    function handleThings(name, opts = {}) {\n      // ...\n    }\n    ```\n\n  \u003ca name=\"7.10\"\u003e\u003c/a\u003e\n  \u003ca name=\"functions--constructor\"\u003e\u003c/a\u003e\n\n  - [7.10](#functions--constructor) 不要用函数构造器创建函数。eslint: [`no-new-func`](http://eslint.org/docs/rules/no-new-func)\n\n    \u003e 为什么？以这种方式创建函数将类似于字符串 eval()，存在漏洞。\n\n    ```javascript\n    // bad\n    const add = new Function('a', 'b', 'return a + b');\n\n    // still bad\n    const subtract = Function('a', 'b', 'return a - b');\n    ```\n\n  \u003ca name=\"7.11\"\u003e\u003c/a\u003e\n  \u003ca name=\"functions--signature-spacing\"\u003e\u003c/a\u003e\n  - [7.11](#functions--signature-spacing) 函数定义部分要有空格。eslint: [`space-before-function-paren`](http://eslint.org/docs/rules/space-before-function-paren) [`space-before-blocks`](http://eslint.org/docs/rules/space-before-blocks)\n\n    \u003e 为什么？统一性好，而且在你添加/删除一个名字的时候不需要添加/删除空格。\n\n    ```javascript\n    // bad\n    const f = function(){};\n    const g = function (){};\n    const h = function() {};\n\n    // good\n    const x = function () {};\n    const y = function a() {};\n    ```\n\n  \u003ca name=\"7.12\"\u003e\u003c/a\u003e\n  \u003ca name=\"functions--mutate-params\"\u003e\u003c/a\u003e\n\n  - [7.12](#functions--mutate-params) 不要修改参数. eslint: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign)\n\n    \u003e 为什么？操作参数对象对原始调用者会导致意想不到的副作用。就是不要改参数的数据结构，保留参数原始值和数据结构。\n\n    ```javascript\n    // bad\n    function f1(obj) {\n      obj.key = 1;\n    };\n\n    // good\n    function f2(obj) {\n      const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;\n    };\n    ```\n\n  \u003ca name=\"7.13\"\u003e\u003c/a\u003e\n  \u003ca name=\"functions--reassign-params\"\u003e\u003c/a\u003e\n  - [7.13](#functions--reassign-params) 不要对参数重新赋值。eslint: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign)\n\n    \u003e 为什么？参数重新赋值会导致意外行为，尤其是对 `arguments`。这也会导致优化问题，特别是在 V8 引擎里。\n\n    ```javascript\n    // bad\n    function f1(a) {\n      a = 1;\n      // ...\n    }\n\n    function f2(a) {\n      if (!a) { a = 1; }\n      // ...\n    }\n\n    // good\n    function f3(a) {\n      const b = a || 1;\n      // ...\n    }\n\n    function f4(a = 1) {\n      // ...\n    }\n    ```\n\n  \u003ca name=\"7.14\"\u003e\u003c/a\u003e\n  \u003ca name=\"functions--spread-vs-apply\"\u003e\u003c/a\u003e\n\n  - [7.14](#functions--spread-vs-apply) 使用拓展运算符调用多参数的函数。eslint: [`prefer-spread`](http://eslint.org/docs/rules/prefer-spread)\n\n    \u003e 为什么？这样更清晰，你不必提供上下文（即指定 this 值），而且你不能轻易地用 `apply` 来组成 `new`。\n\n    ```javascript\n    // bad\n    const x = [1, 2, 3, 4, 5];\n    console.log.apply(console, x);\n\n    // good\n    const x = [1, 2, 3, 4, 5];\n    console.log(...x);\n\n    // bad\n    new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));\n\n    // good\n    new Date(...[2016, 8, 5]);\n    ```\n\n  \u003ca name=\"7.15\"\u003e\u003c/a\u003e\n  \u003ca name=\"functions--signature-invocation-indentation\"\u003e\u003c/a\u003e\n  - [7.15](#functions--signature-invocation-indentation) 调用或者编写一个包含多个参数的函数的缩进，应该像这个指南里的其他多行代码写法一样——即每行只包含一个参数，每行逗号结尾。\n\n    ```javascript\n    // bad\n    function foo(bar,\n                 baz,\n                 quux) {\n      // ...\n    }\n\n    // good 缩进不要太过分\n    function foo(\n      bar,\n      baz,\n      quux,\n    ) {\n      // ...\n    }\n\n    // bad\n    console.log(foo,\n      bar,\n      baz);\n\n    // good\n    console.log(\n      foo,\n      bar,\n      baz,\n    );\n    ```\n\n**[⬆ 返回顶部](#目录)**\n\n## 箭头函数\n\n  \u003ca name=\"8.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"arrows--use-them\"\u003e\u003c/a\u003e\n\n  - [8.1](#arrows--use-them) 当你一定要用函数表达式（在回调函数里）的时候，使用箭头函数。 eslint: [`prefer-arrow-callback`](http://eslint.org/docs/rules/prefer-arrow-callback), [`arrow-spacing`](http://eslint.org/docs/rules/arrow-spacing)\n\n    \u003e 为什么？箭头函数中的 `this` 与定义该函数的上下文中的 `this` 一致，这通常才是你想要的。而且箭头函数是更简洁的语法。\n\n    \u003e 什么时候不用箭头函数：如果你的函数逻辑较复杂，你应该把它单独写入一个命名函数里头。\n\n    ```javascript\n    // bad\n    [1, 2, 3].map(function (x) {\n      const y = x + 1;\n      return x * y;\n    });\n\n    // good\n    [1, 2, 3].map((x) =\u003e {\n      const y = x + 1;\n      return x * y;\n    });\n    ```\n\n  \u003ca name=\"8.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"arrows--implicit-return\"\u003e\u003c/a\u003e\n  - [8.2](#arrows--implicit-return) 如果函数体由一个没有副作用的 [表达式](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions) 语句组成，删除大括号和 return。否则，使用大括号和  `return` 语句。 eslint: [`arrow-parens`](https://eslint.org/docs/rules/arrow-parens), [`arrow-body-style`](https://eslint.org/docs/rules/arrow-body-style)\n\n    \u003e 为什么？语法糖，当多个函数链在一起的时候好读。\n\n    ```javascript\n    // bad map 没有 return\n    [1, 2, 3].map((number) =\u003e {\n      const nextNumber = number + 1;\n      `A string containing the ${nextNumber}.`;\n    });\n\n    // good\n    [1, 2, 3].map((number) =\u003e `A string containing the ${number + 1}.`);\n\n    // good\n    [1, 2, 3].map((number) =\u003e {\n      const nextNumber = number + 1;\n      return `A string containing the ${nextNumber}.`;\n    });\n\n    // good\n    [1, 2, 3].map((number, index) =\u003e ({\n      [index]: number,\n    }));\n\n    // 没有明显的存在副作用的 return 语句\n    function foo(callback) {\n      const val = callback();\n      if (val === true) {\n        // 当 callback 返回 true 时在这里执行\n      }\n    }\n\n    let bool = false;\n\n    // bad\n    foo(() =\u003e bool = true);\n\n\n    // good\n    foo(() =\u003e {\n      bool = true;\n    });\n    ```\n\n  \u003ca name=\"8.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"arrows--paren-wrap\"\u003e\u003c/a\u003e\n\n  - [8.3](#arrows--paren-wrap) 如果表达式涉及多行，把他包裹在圆括号里以提高可读性。\n\n    \u003e 为什么？这样能清晰地显示函数的开始位置和结束位置。\n\n    ```js\n    // bad\n    ['get', 'post', 'put'].map((httpMethod) =\u003e Object.prototype.hasOwnProperty.call(\n        httpMagicObjectWithAVeryLongName,\n        httpMethod\n      )\n    );\n\n    // good\n    ['get', 'post', 'put'].map((httpMethod) =\u003e (\n      Object.prototype.hasOwnProperty.call(\n        httpMagicObjectWithAVeryLongName,\n        httpMethod\n      )\n    ));\n    ```\n\n  \u003ca name=\"8.4\"\u003e\u003c/a\u003e\n  \u003ca name=\"arrows--one-arg-parens\"\u003e\u003c/a\u003e\n\n  - [8.4](#arrows--one-arg-parens) 在箭头函数参数两头，总是使用小括号包裹住参数，这样做使代码更清晰且一致. eslint: [`arrow-parens`](https://eslint.org/docs/rules/arrow-parens)\n\n    \u003e 为什么？当你想要添加或删除参数时改动最小。\n\n    ```js\n    // bad\n    [1, 2, 3].map(x =\u003e x * x);\n\n    // good\n    [1, 2, 3].map((x) =\u003e x * x);\n\n    // bad\n    [1, 2, 3].map(number =\u003e (\n      `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`\n    ));\n\n    // good\n    [1, 2, 3].map((number) =\u003e (\n      `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`\n    ));\n\n\n    // bad\n    [1, 2, 3].map(x =\u003e {\n      const y = x + 1;\n      return x * y;\n    });\n\n    // good\n    [1, 2, 3].map((x) =\u003e {\n      const y = x + 1;\n      return x * y;\n    });\n    ```\n\n  \u003ca name=\"8.5\"\u003e\u003c/a\u003e\n  \u003ca name=\"arrows--confusing\"\u003e\u003c/a\u003e\n\n  - [8.5](#arrows--confusing) 避免箭头函数（`=\u003e`）和比较操作符（`\u003c=`, `\u003e=`）混淆. eslint: [`no-confusing-arrow`](http://eslint.org/docs/rules/no-confusing-arrow)\n\n    ```js\n    // bad\n    const itemHeight = (item) =\u003e item.height \u003c= 256 ? item.largeSize : item.smallSize;\n\n    // bad\n    const itemHeight = (item) =\u003e item.height \u003e= 256 ? item.largeSize : item.smallSize;\n\n    // good\n    const itemHeight = (item) =\u003e (item.height \u003c= 256 ? item.largeSize : item.smallSize);\n\n    // good\n    const itemHeight = (item) =\u003e {\n      const { height, largeSize, smallSize } = item;\n      return height \u003c= 256 ? largeSize : smallSize;\n    };\n    ```\n\n  \u003ca name=\"8.6\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--implicit-arrow-linebreak\"\u003e\u003c/a\u003e\n\n  - [8.6](#whitespace--implicit-arrow-linebreak) 使箭头函数体有一个清晰的返回。 eslint: [`implicit-arrow-linebreak`](https://eslint.org/docs/rules/implicit-arrow-linebreak)\n\n    ```javascript\n    // bad\n    (foo) =\u003e\n      bar;\n\n    (foo) =\u003e\n      (bar);\n\n    // good\n    (foo) =\u003e bar;\n    (foo) =\u003e (bar);\n    (foo) =\u003e (\n       bar\n    )\n    ```\n\n**[⬆ 返回顶部](#目录)**\n\n\n## 类与构造函数\n\n  \u003ca name=\"9.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"constructors--use-class\"\u003e\u003c/a\u003e\n  - [9.1](#constructors--use-class) 使用 `class` 语法。避免直接操作 `prototype`。\n\n    \u003e 为什么？`class` 语法更简洁更易理解。\n\n    ```javascript\n    // bad\n    function Queue(contents = []) {\n      this.queue = [...contents];\n    }\n    Queue.prototype.pop = function () {\n      const value = this.queue[0];\n      this.queue.splice(0, 1);\n      return value;\n    };\n\n    // good\n    class Queue {\n      constructor(contents = []) {\n        this.queue = [...contents];\n      }\n      pop() {\n        const value = this.queue[0];\n        this.queue.splice(0, 1);\n        return value;\n      }\n    }\n    ```\n\n  \u003ca name=\"9.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"constructors--extends\"\u003e\u003c/a\u003e\n\n  - [9.2](#constructors--extends) 用 `extends` 实现继承。\n\n    \u003e 为什么？它是一种内置的方法来继承原型功能而不破坏 `instanceof`。\n\n    ```javascript\n    // bad\n    const inherits = require('inherits');\n    function PeekableQueue(contents) {\n      Queue.apply(this, contents);\n    }\n    inherits(PeekableQueue, Queue);\n    PeekableQueue.prototype.peek = function () {\n      return this.queue[0];\n    }\n\n    // good\n    class PeekableQueue extends Queue {\n      peek() {\n        return this.queue[0];\n      }\n    }\n    ```\n\n  \u003ca name=\"9.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"constructors--chaining\"\u003e\u003c/a\u003e\n  - [9.3](#constructors--chaining) 方法可以返回 `this` 来实现链式调用。\n\n    ```javascript\n    // bad\n    Jedi.prototype.jump = function () {\n      this.jumping = true;\n      return true;\n    };\n\n    Jedi.prototype.setHeight = function (height) {\n      this.height = height;\n    };\n\n    const luke = new Jedi();\n    luke.jump(); // =\u003e true\n    luke.setHeight(20); // =\u003e undefined\n\n    // good\n    class Jedi {\n      jump() {\n        this.jumping = true;\n        return this;\n      }\n\n      setHeight(height) {\n        this.height = height;\n        return this;\n      }\n    }\n\n    const luke = new Jedi();\n\n    luke.jump()\n      .setHeight(20);\n    ```\n\n\n  \u003ca name=\"9.4\"\u003e\u003c/a\u003e\n  \u003ca name=\"constructors--tostring\"\u003e\u003c/a\u003e\n  - [9.4](#constructors--tostring) 自己写 `toString()` 方法是可以的，但需要保证它可以正常工作且没有副作用。\n\n    ```javascript\n    class Jedi {\n      constructor(options = {}) {\n        this.name = options.name || 'no name';\n      }\n\n      getName() {\n        return this.name;\n      }\n\n      toString() {\n        return `Jedi - ${this.getName()}`;\n      }\n    }\n    ```\n\n  \u003ca name=\"9.5\"\u003e\u003c/a\u003e\n  \u003ca name=\"constructors--no-useless\"\u003e\u003c/a\u003e\n  - [9.5](#constructors--no-useless) 如果没有特别定义，类有默认的构造方法。一个空的构造函数或只是代表父类的构造函数是不需要写的。 eslint: [`no-useless-constructor`](http://eslint.org/docs/rules/no-useless-constructor)\n\n    ```javascript\n    // bad\n    class Jedi {\n      constructor() {}\n\n      getName() {\n        return this.name;\n      }\n    }\n\n    // bad\n    class Rey extends Jedi {\n      // 这种构造函数是不需要写的\n      constructor(...args) {\n        super(...args);\n      }\n    }\n\n    // good\n    class Rey extends Jedi {\n      constructor(...args) {\n        super(...args);\n        this.name = 'Rey';\n      }\n    }\n    ```\n\n  \u003ca name=\"9.6\"\u003e\u003c/a\u003e\n  \u003ca name=\"classes--no-duplicate-members\"\u003e\u003c/a\u003e\n  - [9.6](#classes--no-duplicate-members) 避免重复定义类成员。eslint: [`no-dupe-class-members`](http://eslint.org/docs/rules/no-dupe-class-members)\n\n    \u003e 为什么？重复定义类成员只会使用最后一个被定义的 —— 重复本身也是一个 bug.\n\n    ```javascript\n    // bad\n    class Foo {\n      bar() { return 1; }\n      bar() { return 2; }\n    }\n\n    // good\n    class Foo {\n      bar() { return 1; }\n    }\n\n    // good\n    class Foo {\n      bar() { return 2; }\n    }\n    ```\n\n \u003ca name=\"classes--methods-use-this\"\u003e\u003c/a\u003e\n  - [9.7](#classes--methods-use-this) 除非外部库或框架需要使用特定的非静态方法，否则类方法应该使用 `this` 或被写成静态方法。\n    作为一个实例方法表明它应该根据实例的属性有不同的行为。eslint: [`class-methods-use-this`](https://eslint.org/docs/rules/class-methods-use-this)\n\n    ```javascript\n    // bad\n    class Foo {\n      bar() {\n        console.log('bar');\n      }\n    }\n\n    // good - this 被使用了\n    class Foo {\n      bar() {\n        console.log(this.bar);\n      }\n    }\n\n    // good - constructor 不一定要使用 this\n    class Foo {\n      constructor() {\n        // ...\n      }\n    }\n\n    // good - 静态方法不需要使用 this\n    class Foo {\n      static bar() {\n        console.log('bar');\n      }\n    }\n    ```\n\n**[⬆ 返回顶部](#目录)**\n\n## 模块\n\n  \u003ca name=\"10.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"modules--use-them\"\u003e\u003c/a\u003e\n\n  - [10.1](#modules--use-them) 使用（`import`/`export`）模块而不是非标准的模块系统。你可以随时转到你喜欢的模块系统。\n\n    \u003e 为什么？模块化是未来，让我们现在就开启未来吧。\n\n    ```javascript\n    // bad\n    const AirbnbStyleGuide = require('./AirbnbStyleGuide');\n    module.exports = AirbnbStyleGuide.es6;\n\n    // ok\n    import AirbnbStyleGuide from './AirbnbStyleGuide';\n    export default AirbnbStyleGuide.es6;\n\n    // best\n    import { es6 } from './AirbnbStyleGuide';\n    export default es6;\n    ```\n\n  \u003ca name=\"10.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"modules--no-wildcard\"\u003e\u003c/a\u003e\n  - [10.2](#modules--no-wildcard) 不要用 `import` 通配符， 即 `*` 这种方式。\n\n    \u003e 为什么？这确保你有单个默认的导出。\n\n    ```javascript\n    // bad\n    import * as AirbnbStyleGuide from './AirbnbStyleGuide';\n\n    // good\n    import AirbnbStyleGuide from './AirbnbStyleGuide';\n    ```\n\n  \u003ca name=\"10.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"modules--no-export-from-import\"\u003e\u003c/a\u003e\n\n  - [10.3](#modules--no-export-from-import) 不要直接从 `import` 中直接 `export`。\n\n    \u003e 为什么？虽然只写一行很简洁，但是使用明确 `import` 和明确的 `export` 来保证一致性。\n\n    ```javascript\n    // bad\n    // filename es6.js\n    export { es6 as default } from './AirbnbStyleGuide';\n\n    // good\n    // filename es6.js\n    import { es6 } from './AirbnbStyleGuide';\n    export default es6;\n    ```\n\n  \u003ca name=\"10.4\"\u003e\u003c/a\u003e\n  \u003ca name=\"modules--no-duplicate-imports\"\u003e\u003c/a\u003e\n\n  - [10.4](#modules--no-duplicate-imports) 一个路径只 `import` 一次。eslint: [`no-duplicate-imports`](http://eslint.org/docs/rules/no-duplicate-imports)\n\n    \u003e 为什么？多行导入同一路径将使代码变得难以维护。\n\n    ```javascript\n    // bad\n    import foo from 'foo';\n    // … 其他导入 … //\n    import { named1, named2 } from 'foo';\n\n    // good\n    import foo, { named1, named2 } from 'foo';\n\n    // good\n    import foo, {\n      named1,\n      named2,\n    } from 'foo';\n    ```\n\n  \u003ca name=\"10.5\"\u003e\u003c/a\u003e\n  \u003ca name=\"modules--no-mutable-exports\"\u003e\u003c/a\u003e\n\n  - [10.5](#modules--no-mutable-exports) 不要导出可变的东西。eslint: [`import/no-mutable-exports`](https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md)\n\n    \u003e 为什么？变化通常都是需要避免，特别是当你要输出可变的绑定。虽然在某些场景下可能需要这种技术，但总的来说应该导出常量。\n\n    ```javascript\n    // bad\n    let foo = 3;\n    export { foo }\n\n    // good\n    const foo = 3;\n    export { foo }\n    ```\n\n  \u003ca name=\"10.6\"\u003e\u003c/a\u003e\n  \u003ca name=\"modules--prefer-default-export\"\u003e\u003c/a\u003e\n\n  - [10.6](#modules--prefer-default-export) 在一个单一导出模块里，用 `export default` 更好。eslint: [`import/prefer-default-export`](https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md)\n\n    \u003e 为什么？鼓励使用更多文件，每个文件只导出一次，这样可读性和可维护性更好。\n\n    ```javascript\n    // bad\n    export function foo() {}\n\n    // good\n    export default function foo() {}\n    ```\n\n  \u003ca name=\"10.7\"\u003e\u003c/a\u003e\n  \u003ca name=\"modules--imports-first\"\u003e\u003c/a\u003e\n\n  - [10.7](#modules--imports-first) 把 `import` 放在其他所有语句之前。eslint: [`import/first`](https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/first.md)\n\n    \u003e 为什么？因为 `import` 会被提升到代码最前面运行，因此将他们放在最前面以防止发生意外行为。\n\n    ```javascript\n    // bad\n    import foo from 'foo';\n    foo.init();\n\n    import bar from 'bar';\n\n    // good\n    import foo from 'foo';\n    import bar from 'bar';\n\n    foo.init();\n    ```\n\n  \u003ca name=\"10.8\"\u003e\u003c/a\u003e\n  \u003ca name=\"modules--multiline-imports-over-newlines\"\u003e\u003c/a\u003e\n  - [10.8](#modules--multiline-imports-over-newlines) 多行 `import` 应该缩进，就像多行数组和对象字面量一样。eslint: [`object-curly-newline`](https://eslint.org/docs/rules/object-curly-newline)\n\n    \u003e 为什么？花括号与样式指南中每个其他花括号块遵循相同的缩进规则，逗号也是。\n\n    ```javascript\n    // bad\n    import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';\n\n    // good\n    import {\n      longNameA,\n      longNameB,\n      longNameC,\n      longNameD,\n      longNameE,\n    } from 'path';\n    ```\n\n  \u003ca name=\"10.9\"\u003e\u003c/a\u003e\n  \u003ca name=\"modules--no-webpack-loader-syntax\"\u003e\u003c/a\u003e\n  - [10.9](#modules--no-webpack-loader-syntax) 在 `import` 语句里不允许 Webpack loader 语法。eslint: [`import/no-webpack-loader-syntax`](https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/no-webpack-loader-syntax.md)\n\n    \u003e 为什么？一旦用 Webpack 语法在 import 里会把代码耦合到模块绑定器。最好是在 `webpack.config.js` 里写 webpack loader 语法\n\n    ```javascript\n    // bad\n    import fooSass from 'css!sass!foo.scss';\n    import barCss from 'style!css!bar.css';\n\n    // good\n    import fooSass from 'foo.scss';\n    import barCss from 'bar.css';\n    ```\n\n  \u003ca name=\"10.10\"\u003e\u003c/a\u003e\n  \u003ca name=\"modules--import-extensions\"\u003e\u003c/a\u003e\n  - [10.10](#modules--import-extensions) import JavaScript文件不用包含扩展名\n eslint: [`import/extensions`](https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/extensions.md)\n    \u003e 为什么? 使用扩展名重构不友好，而且让模块使用者去了解模块的实现细节是不合适的。\n\n    ```javascript\n    // bad\n    import foo from './foo.js';\n    import bar from './bar.jsx';\n    import baz from './baz/index.jsx';\n\n    // good\n    import foo from './foo';\n    import bar from './bar';\n    import baz from './baz';\n    ```\n\n**[⬆ 返回顶部](#目录)**\n\n## 迭代器与生成器\n\n  \u003ca name=\"11.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"iterators--nope\"\u003e\u003c/a\u003e\n  - [11.1](#iterators--nope) 不要用迭代器。使用 JavaScript 高级函数代替 `for-in`、 `for-of`。eslint: [`no-iterator`](http://eslint.org/docs/rules/no-iterator) [`no-restricted-syntax`](http://eslint.org/docs/rules/no-restricted-syntax)\n\n    \u003e 为什么？这强调了我们不可变的规则。 处理返回值的纯函数比处理副作用更容易。\n\n    \u003e 用数组的这些迭代方法： `map()` / `every()` / `filter()` / `find()` / `findIndex()` / `reduce()` / `some()` / ... , 用对象的这些方法 `Object.keys()` / `Object.values()` / `Object.entries()`  去产生一个数组，这样你就能去遍历对象了。\n\n    ```javascript\n    const numbers = [1, 2, 3, 4, 5];\n\n    // bad\n    let sum = 0;\n    for (let num of numbers) {\n      sum += num;\n    }\n    sum === 15;\n\n    // good\n    let sum = 0;\n    numbers.forEach((num) =\u003e sum += num);\n    sum === 15;\n\n    // best (use the functional force)\n    const sum = numbers.reduce((total, num) =\u003e total + num, 0);\n    sum === 15;\n\n    // bad\n    const increasedByOne = [];\n    for (let i = 0; i \u003c numbers.length; i++) {\n      increasedByOne.push(numbers[i] + 1);\n    }\n\n        // good\n    const increasedByOne = [];\n    numbers.forEach((num) =\u003e {\n      increasedByOne.push(num + 1);\n    });\n\n    // best (keeping it functional)\n    const increasedByOne = numbers.map((num) =\u003e num + 1);\n    ```\n\n  \u003ca name=\"11.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"generators--nope\"\u003e\u003c/a\u003e\n  - [11.2](#generators--nope) 现在暂时不要使用生成器。\n\n    \u003e 为什么？生成器目前不能很好地转换为 ES5 语法。\n\n  \u003ca name=\"11.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"generators--spacing\"\u003e\u003c/a\u003e\n\n  - [11.3](#generators--spacing) 如果你一定要用生成器，或者你忽略 [我们的建议](#generators--nope)，请确保它们的函数标志空格是得当的。eslint: [`generator-star-spacing`](http://eslint.org/docs/rules/generator-star-spacing)\n\n    \u003e 为什么？`function` 和 `*` 是同一概念关键字 - `*`不是`function`的修饰符，`function*` 是一个和`function` 不一样的独特结构。\n\n    ```js\n    // bad\n    function * foo() {\n      // ...\n    }\n\n    // bad\n    const bar = function * () {\n      // ...\n    }\n\n    // bad\n    const baz = function *() {\n      // ...\n    }\n\n    // bad\n    const quux = function*() {\n      // ...\n    }\n\n    // bad\n    function*foo() {\n      // ...\n    }\n\n    // bad\n    function *foo() {\n      // ...\n    }\n\n    // very bad\n    function\n    *\n    foo() {\n      // ...\n    }\n\n    // very bad\n    const wat = function\n    *\n    () {\n      // ...\n    }\n\n    // good\n    function* foo() {\n      // ...\n    }\n\n    // good\n    const foo = function* () {\n      // ...\n    }\n    ```\n\n**[⬆ 返回顶部](#目录)**\n\n\n## 属性\n\n  \u003ca name=\"12.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"properties--dot\"\u003e\u003c/a\u003e\n\n  - [12.1](#properties--dot) 访问属性时使用点符号。eslint: [`dot-notation`](http://eslint.org/docs/rules/dot-notation)\n\n    ```javascript\n    const luke = {\n      jedi: true,\n      age: 28,\n    };\n\n    // bad\n    const isJedi = luke['jedi'];\n\n    // good\n    const isJedi = luke.jedi;\n    ```\n\n  \u003ca name=\"12.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"properties--bracket\"\u003e\u003c/a\u003e\n\n  - [12.2](#properties--bracket) 当使用变量获取属性时用方括号 `[]`。\n\n    ```javascript\n    const luke = {\n      jedi: true,\n      age: 28,\n    };\n\n    function getProp(prop) {\n      return luke[prop];\n    }\n\n    const isJedi = getProp('jedi');\n    ```\n\n  \u003ca name=\"12.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"es2016-properties--exponentiation-operator\"\u003e\u003c/a\u003e\n  - [12.3](#es2016-properties--exponentiation-operator) 做幂运算时用幂操作符 `**` 。eslint: [`prefer-exponentiation-operator`](https://eslint.org/docs/rules/prefer-exponentiation-operator)。\n\n    ```javascript\n    // bad\n    const binary = Math.pow(2, 10);\n\n    // good\n    const binary = 2 ** 10;\n    ```\n\n**[⬆ 返回顶部](#目录)**\n\n\n## 变量\n\n  \u003ca name=\"13.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"variables--const\"\u003e\u003c/a\u003e\n\n  - [13.1](#variables--const)  使用 `const` 或 `let` 声明变量。不这样做会导致全局变量。我们想要避免污染全局命名空间。地球超人也这样警告我们（译者注：可能是一个冷笑话）。 eslint: [`no-undef`](http://eslint.org/docs/rules/no-undef) [`prefer-const`](http://eslint.org/docs/rules/prefer-const)\n\n    ```javascript\n    // bad\n    superPower = new SuperPower();\n\n    // good\n    const superPower = new SuperPower();\n    ```\n\n  \u003ca name=\"13.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"variables--one-const\"\u003e\u003c/a\u003e\n\n  - [13.2](#variables--one-const) 为每个变量声明都用一个 `const` 或 `let `。eslint: [`one-var`](http://eslint.org/docs/rules/one-var)\n\n    \u003e 为什么？这种方式很容易去声明新的变量，你不用去考虑把 `;` 调换成 `,`，或者引入一个只有标点的不同的变化（译者注：这里说的应该是在 Git 提交代码时显示的变化）。这种做法也可以是你在调试的时候单步每个声明语句，而不是一下跳过所有声明。\n\n    ```javascript\n    // bad\n    const items = getItems(),\n        goSportsTeam = true,\n        dragonball = 'z';\n\n    // bad\n    // （与前面的比较，找一找错误）\n    const items = getItems(),\n        goSportsTeam = true;\n        dragonball = 'z';\n\n    // good\n    const items = getItems();\n    const goSportsTeam = true;\n    const dragonball = 'z';\n    ```\n\n  \u003ca name=\"13.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"variables--const-let-group\"\u003e\u003c/a\u003e\n\n  - [13.3](#variables--const-let-group) 把`const`  和 `let` 分别放一起。\n\n    \u003e 为什么？在你需要分配一个新的变量，而这个变量依赖之前分配过的变量的时候，这种做法是有帮助的。\n\n    ```javascript\n    // bad\n    let i, len, dragonball,\n        items = getItems(),\n        goSportsTeam = true;\n\n    // bad\n    let i;\n    const items = getItems();\n    let dragonball;\n    const goSportsTeam = true;\n    let len;\n\n    // good\n    const goSportsTeam = true;\n    const items = getItems();\n    let dragonball;\n    let i;\n    let length;\n    ```\n\n  \u003ca name=\"13.4\"\u003e\u003c/a\u003e\n  \u003ca name=\"variables--define-where-used\"\u003e\u003c/a\u003e\n  - [13.4](#variables--define-where-used) 在你需要的地方声明变量，但是要放在合理的位置。\n\n    \u003e 为什么？`let` 和 `const` 都是块级作用域而不是函数级作用域。\n\n    ```javascript\n    // bad - 不必要的函数调用。\n    function checkName(hasName) {\n      const name = getName();\n\n      if (hasName === 'test') {\n        return false;\n      }\n\n      if (name === 'test') {\n        this.setName('');\n        return false;\n      }\n\n      return name;\n    }\n\n    // good\n    function checkName(hasName) {\n      if (hasName === 'test') {\n        return false;\n      }\n\n      // 在需要的时候分配\n      const name = getName();\n\n      if (name === 'test') {\n        this.setName('');\n        return false;\n      }\n\n      return name;\n    }\n    ```\n    \u003ca name=\"13.5\"\u003e\u003c/a\u003e\n    \u003ca name=\"variables--no-chain-assignment\"\u003e\u003c/a\u003e\n  - [13.5](#variables--no-chain-assignment) 不要使用链式声明变量。 eslint: [`no-multi-assign`](https://eslint.org/docs/rules/no-multi-assign)\n\n    \u003e 为什么？链式声明变量会创建隐式全局变量。\n\n    ```javascript\n    // bad\n    (function example() {\n      // JavaScript 将这一段解释为\n      // let a = ( b = ( c = 1 ) );\n      // let 只对变量 a 起作用; 变量 b 和 c 都变成了全局变量\n      let a = b = c = 1;\n    }());\n\n    console.log(a); // undefined\n    console.log(b); // 1\n    console.log(c); // 1\n\n    // good\n    (function example() {\n      let a = 1;\n      let b = a;\n      let c = a;\n    }());\n\n    console.log(a); // undefined\n    console.log(b); // undefined\n    console.log(c); // undefined\n\n    // `const` 也是如此\n    ```\n\n  \u003ca name=\"13.6\"\u003e\u003c/a\u003e\n  \u003ca name=\"variables--unary-increment-decrement\"\u003e\u003c/a\u003e\n\n  - [13.6](#variables--unary-increment-decrement) 不要使用一元自增自减运算符（`++`， `--`）. eslint [`no-plusplus`](http://eslint.org/docs/rules/no-plusplus)\n\n    \u003e 为什么？根据 eslint 文档，一元增量和减量语句受到自动分号插入的影响，并且可能会导致应用程序中的值递增或递减的静默错误。 使用 `num + = 1` 而不是 `num ++` 或 `num ++` 语句也是含义清晰的。 禁止一元增量和减量语句还会阻止您无意地预增/预减值，这也会导致程序出现意外行为。\n\n    ```javascript\n      // bad\n\n      const array = [1, 2, 3];\n      let num = 1;\n      num++;\n      --num;\n\n      let sum = 0;\n      let truthyCount = 0;\n      for (let i = 0; i \u003c array.length; i++) {\n        let value = array[i];\n        sum += value;\n        if (value) {\n          truthyCount++;\n        }\n      }\n\n      // good\n\n      const array = [1, 2, 3];\n      let num = 1;\n      num += 1;\n      num -= 1;\n\n      const sum = array.reduce((a, b) =\u003e a + b, 0);\n      const truthyCount = array.filter(Boolean).length;\n    ```\n\n  \u003ca name=\"13.7\"\u003e\u003c/a\u003e\n  \u003ca name=\"variables--linebreak\"\u003e\u003c/a\u003e\n\n  - [13.7](#variables--linebreak) 在赋值的时候避免在 `=` 前/后换行。 如果你的赋值语句超出 [`max-len`](https://eslint.org/docs/rules/max-len)，那就用小括号把这个值包起来再换行。eslint [`operator-linebreak`](https://eslint.org/docs/rules/operator-linebreak).\n\n    \u003e 为什么？在 `=` 附近换行容易混淆这个赋值语句。\n\n    ```javascript\n    // bad\n    const foo =\n      superLongLongLongLongLongLongLongLongFunctionName();\n\n    // bad\n    const foo\n      = 'superLongLongLongLongLongLongLongLongString';\n\n    // good\n    const foo = (\n      superLongLongLongLongLongLongLongLongFunctionName()\n    );\n\n    // good\n    const foo = 'superLongLongLongLongLongLongLongLongString';\n    ```\n\n  \u003ca name=\"13.8\"\u003e\u003c/a\u003e\n  \u003ca name=\"variables--no-unused-vars\"\u003e\u003c/a\u003e\n\n  - [13.8](#variables--no-unused-vars) 不允许有未使用的变量。eslint: [`no-unused-vars`](https://eslint.org/docs/rules/no-unused-vars)\n\n    \u003e 为什么？一个声明了但未使用的变量更像是由于重构未完成产生的错误。这种在代码中出现的变量会使阅读者迷惑。\n\n    ```javascript\n    // bad\n\n    const some_unused_var = 42;\n\n    // 写了没用\n    let y = 10;\n    y = 5;\n\n    // 变量改了自己的值，也没有用这个变量\n    let z = 0;\n    z = z + 1;\n\n    // 参数定义了但未使用\n    function getX(x, y) {\n        return x;\n    }\n\n    // good\n    function getXPlusY(x, y) {\n      return x + y;\n    }\n\n    const x = 1;\n    const y = a + 2;\n\n    alert(getXPlusY(x, y));\n\n    // 'type' 即使没有使用也可以可以被忽略， 因为这个有一个 rest 取值的属性。\n    // 这是从对象中抽取一个忽略特殊字段的对象的一种形式\n    const { type, ...coords } = data;\n    // 'coords' 现在就是一个没有 'type' 属性的 'data' 对象\n    ```\n\n**[⬆ 返回顶部](#目录)**\n\n## 提升\n\n  \u003ca name=\"14.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"hoisting--about\"\u003e\u003c/a\u003e\n\n  - [14.1](#hoisting--about) `var` 声明会被提前到离他最近的作用域的最前面，但是它的赋值语句并没有提前。`const` 和 `let` 被赋予了新的概念 [暂时性死区 (TDZ)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#temporal_dead_zone_tdz)。 重要的是要知道为什么 [typeof 不再安全](https://web.archive.org/web/20200121061528/http://es-discourse.com/t/why-typeof-is-no-longer-safe/15)。\n\n    ```javascript\n    // 我们知道这个不会工作，假设没有定义全局的 notDefined\n    function example() {\n      console.log(notDefined); // =\u003e throws a ReferenceError\n    }\n\n    // 在你引用的地方之后声明一个变量，他会正常输出是因为变量提升。\n    // 注意： declaredButNotAssigned 的值 true 没有被提升。\n    function example() {\n      console.log(declaredButNotAssigned); // =\u003e undefined\n      var declaredButNotAssigned = true;\n    }\n\n    // 解释器把变量声明提升到作用域最前面，\n    // 可以重写成如下例子， 二者意义相同。\n    function example() {\n      let declaredButNotAssigned;\n      console.log(declaredButNotAssigned); // =\u003e undefined\n      declaredButNotAssigned = true;\n    }\n\n    // 用 const，let就不一样了。\n    function example() {\n      console.log(declaredButNotAssigned); // =\u003e throws a ReferenceError\n      console.log(typeof declaredButNotAssigned); // =\u003e throws a ReferenceError\n      const declaredButNotAssigned = true;\n    }\n    ```\n\n  \u003ca name=\"14.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"hoisting--anon-expressions\"\u003e\u003c/a\u003e\n\n  - [14.2](#hoisting--anon-expressions) 匿名函数表达式和 `var` 情况相同。\n\n    ```javascript\n    function example() {\n      console.log(anonymous); // =\u003e undefined\n\n      anonymous(); // =\u003e TypeError anonymous is not a function\n\n      // 译者注，不管后面是函数、数字还是字符串，都是一样的，总结就是实际代码中最好不要用 var。\n      var anonymous = function () {\n        console.log('anonymous function expression');\n      };\n    }\n    ```\n\n  \u003ca name=\"14.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"hoisting--named-expresions\"\u003e\u003c/a\u003e\n  - [14.3](#hoisting--named-expresions) 已命名函数表达式提升他的变量名，不是函数名或函数体。\n\n    ```javascript\n    function example() {\n      console.log(named); // =\u003e undefined\n\n      named(); // =\u003e TypeError named is not a function\n\n      superPower(); // =\u003e ReferenceError superPower is not defined\n\n      var named = function superPower() {\n        console.log('Flying');\n      };\n    }\n\n    // 函数名和变量名一样是也如此。\n    function example() {\n      console.log(named); // =\u003e undefined\n\n      named(); // =\u003e TypeError named is not a function\n\n      var named = function named() {\n        console.log('named');\n      };\n    }\n    ```\n\n  \u003ca name=\"14.4\"\u003e\u003c/a\u003e\n  \u003ca name=\"hoisting--declarations\"\u003e\u003c/a\u003e\n  - [14.4](#hoisting--declarations) 函数声明则提升了函数名和函数体。\n\n    ```javascript\n    function example() {\n      superPower(); // =\u003e Flying\n\n      function superPower() {\n        console.log('Flying');\n      }\n    }\n    ```\n  \u003ca name=\"14.5\"\u003e\u003c/a\u003e\n  \u003ca name=\"no-use-before-define\"\u003e\u003c/a\u003e\n  - [14.5](#no-use-before-define) 变量、类、函数都应该在使用前定义。 eslint: [`no-use-before-define`](https://eslint.org/docs/latest/rules/no-use-before-define)\n\n    \u003e 为什么? 当变量、类或者函数在使用处之后定义，这让阅读者很难想到这个函数引用自何处。 对于读者在遇到某个事物之前，如果能知道这个事物的来源（不论是在文件中定义还是从别的模块引用），理解起来都会清晰很多。\n\n    ```javascript\n    // 不好的\n\n    // 变量 a 使用出现在定义之前\n    console.log(a); // 这样会导致 undefined，虽然变量声明被提升了， 但 a 初始化复制却还没执行\n    var a = 10;\n\n    // 函数 fun 使用出现在定义之前\n    fun();\n    function fun() {}\n\n    // 类 A 使用出现在定义之前\n    new A(); // 引用错误： 无法在 A 初始化之前访问它\n    class A {\n    }\n\n    // `let` 和 `const` 被提升， 但是他们没有初始化变量值\n    // 变量 a、 b 都被放在了 JavaScript 的暂时性死区 (Temporal Dead Zone， 指在变量被声明之前无法访问它的现象)。\n\n    console.log(a); // 引用错误: 无法在 a 初始化之前访问它\n    console.log(b); // 引用错误: 无法在 b 初始化之前访问它\n    let a = 10;\n    const b = 5;\n\n\n    // 好的\n\n    var a = 10;\n    console.log(a); // 10\n\n    function fun() {}\n    fun();\n\n    class A {\n    }\n    new A();\n\n    let a = 10;\n    const b = 5;\n    console.log(a); // 10\n    console.log(b); // 5\n    ```\n  - 详情请见 [JavaScript Scoping \u0026 Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting/) by [Ben Cherry](http://www.adequatelygood.com/).\n\n**[⬆ 返回顶部](#目录)**\n\n\n## 比较运算符与相等\n\n  \u003ca name=\"15.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"comparison--eqeqeq\"\u003e\u003c/a\u003e\n  - [15.1](#comparison--eqeqeq) 用 `===` 和 `!==` 而不是 `==` 和 `!=`. eslint: [`eqeqeq`](http://eslint.org/docs/rules/eqeqeq)\n\n  \u003ca name=\"15.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"comparison--if\"\u003e\u003c/a\u003e\n\n  - [15.2](#comparison--if) 条件语句如 `if` 语句使用强制 `ToBoolean` 抽象方法来计算它们的表达式，并且始终遵循以下简单规则：\n\n    + **Objects**  计算成 **true**\n    + **Undefined** 计算成 **false**\n    + **Null** 计算成 **false**\n    + **Booleans**  计算成 **the value of the boolean**\n    + **Numbers**\n      + **+0, -0, or NaN** 计算成 **false**\n      + 其他 **true**\n    + **Strings**\n      + `''` 计算成 **false**\n      + 其他 **true**\n\n    ```javascript\n    if ([0] \u0026\u0026 []) {\n      // true\n      // 数组（即使是空数组）是对象，对象会计算成 true\n    }\n    ```\n\n  \u003ca name=\"15.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"comparison--shortcuts\"\u003e\u003c/a\u003e\n  - [15.3](#comparison--shortcuts) 布尔值要用缩写，而字符串和数字要明确使用比较操作符。\n\n    ```javascript\n    // bad\n    if (isValid === true) {\n      // ...\n    }\n\n    // good\n    if (isValid) {\n      // ...\n    }\n\n    // bad\n    if (name) {\n      // ...\n    }\n\n    // good\n    if (name !== '') {\n      // ...\n    }\n\n    // bad\n    if (collection.length) {\n      // ...\n    }\n\n    // good\n    if (collection.length \u003e 0) {\n      // ...\n    }\n    ```\n\n  \u003ca name=\"15.4\"\u003e\u003c/a\u003e\n  \u003ca name=\"comparison--moreinfo\"\u003e\u003c/a\u003e\n\n  - [15.4](#comparison--moreinfo) 更多信息请见 Angus Croll 的 [Truth, Equality, and JavaScript](https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108)。\n\n  \u003ca name=\"15.5\"\u003e\u003c/a\u003e\n  \u003ca name=\"comparison--switch-blocks\"\u003e\u003c/a\u003e\n\n  - [15.5](#comparison--switch-blocks) 在 `case` 和 `default` 分句里用大括号创建一块包含词法声明的区域（例如：`let`、`const`、`function` 和 `class`）。eslint rules: [`no-case-declarations`](http://eslint.org/docs/rules/no-case-declarations).\n\n    \u003e 为什么？词法声明在整个 `switch` 的代码块里都可见，但是只有当其被分配后才会初始化，仅当这个 `case` 被执行时才被初始化。当多个 `case` 分句试图定义同一个对象时就会出现问题。\n\n    ```javascript\n    // bad\n    switch (foo) {\n      case 1:\n        let x = 1;\n        break;\n      case 2:\n        const y = 2;\n        break;\n      case 3:\n        function f() {\n          // ...\n        }\n        break;\n      default:\n        class C {}\n    }\n\n    // good\n    switch (foo) {\n      case 1: {\n        let x = 1;\n        break;\n      }\n      case 2: {\n        const y = 2;\n        break;\n      }\n      case 3: {\n        function f() {\n          // ...\n        }\n        break;\n      }\n      case 4:\n        bar();\n        break;\n      default: {\n        class C {}\n      }\n    }\n    ```\n\n  \u003ca name=\"15.6\"\u003e\u003c/a\u003e\n  \u003ca name=\"comparison--nested-ternaries\"\u003e\u003c/a\u003e\n\n  - [15.6](#comparison--nested-ternaries) 三元表达式不应该嵌套，通常是单行表达式。eslint rules: [`no-nested-ternary`](http://eslint.org/docs/rules/no-nested-ternary)\n\n    ```javascript\n    // bad\n    const foo = maybe1 \u003e maybe2\n      ? \"bar\"\n      : value1 \u003e value2 ? \"baz\" : null;\n\n    // better\n    const maybeNull = value1 \u003e value2 ? 'baz' : null;\n\n    const foo = maybe1 \u003e maybe2\n    ? 'bar'\n      : maybeNull;\n\n    // best\n    const maybeNull = value1 \u003e value2 ? 'baz' : null;\n\n    const foo = maybe1 \u003e maybe2 ? 'bar' : maybeNull;\n    ```\n\n  \u003ca name=\"15.7\"\u003e\u003c/a\u003e\n  \u003ca name=\"comparison--unneeded-ternary\"\u003e\u003c/a\u003e\n  - [15.7](#comparison--unneeded-ternary) 避免不必要的三元表达式。eslint rules: [`no-unneeded-ternary`](http://eslint.org/docs/rules/no-unneeded-ternary)\n\n    ```javascript\n    // bad\n    const foo = a ? a : b;\n    const bar = c ? true : false;\n    const baz = c ? false : true;\n    const quux = a != null ? a : b;\n\n    // good\n    const foo = a || b;\n    const bar = !!c;\n    const baz = !c;\n    const quux = a ?? b;\n    ```\n\n  \u003ca name=\"15.8\"\u003e\u003c/a\u003e\n  \u003ca name=\"comparison--no-mixed-operators\"\u003e\u003c/a\u003e\n  - [15.8](#comparison--no-mixed-operators) 用圆括号来组合多种操作符。唯一里的例外就是像 `+`, `-`, 和 `**` 这种优先级容易理解的运算符。我们还是建议把 `/` `*` 放到小括号里， 因为他们混用的时候优先级容易有歧义。 eslint: [`no-mixed-operators`](https://eslint.org/docs/rules/no-mixed-operators)\n\n    \u003e 为什么？这提高了可读性，并且明确了开发者的意图。\n\n    ```javascript\n    // bad\n    const foo = a \u0026\u0026 b \u003c 0 || c \u003e 0 || d + 1 === 0;\n\n    // bad\n    const bar = a ** b - 5 % d;\n\n    // bad\n    // 别人会陷入(a || b) \u0026\u0026 c 的迷惑中\n    if (a || b \u0026\u0026 c) {\n      return d;\n    }\n\n    // bad\n    const bar = a + b / c * d;\n\n    // good\n    const foo = (a \u0026\u0026 b \u003c 0) || c \u003e 0 || (d + 1 === 0);\n\n    // good\n    const bar = (a ** b) - (5 % d);\n\n    // good\n    if (a || (b \u0026\u0026 c)) {\n      return d;\n    }\n\n    // good\n    const bar = a + (b / c) * d;\n    ```\n  \u003ca name=\"nullish-coalescing-operator\"\u003e\u003c/a\u003e\n  - [15.9](#nullish-coalescing-operator) (`??`) 是一个逻辑运算符， 当运算符左侧是 null 或 undefined 时返回右侧的值， 否则返回左侧值。\n\n    \u003e 为什么? (`??`)这个运算符通过精确区分null/undefined和其他\"falsy\"值，从而增强了代码的清晰度和可预测性。\n\n    ```javascript\n    // 不好的\n    const value = 0 ?? 'default';\n    // returns 0, not 'default'\n\n    // 不好的\n    const value = '' ?? 'default';\n    // returns '', not 'default'\n\n    // 好的\n    const value = null ?? 'default';\n    // returns 'default'\n\n    // 好的\n    const user = {\n      name: 'John',\n      age: null\n    };\n    const age = user.age ?? 18;\n    // returns 18\n    ```\n\n\n**[⬆ back to top](#目录)**\n\n\n## 块\n\n  \u003ca name=\"16.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"blocks--braces\"\u003e\u003c/a\u003e\n  - [16.1](#blocks--braces) 用大括号包裹多行代码块。 eslint: [`nonblock-statement-body-position`](https://eslint.org/docs/rules/nonblock-statement-body-position)\n\n    ```javascript\n    // bad\n    if (test)\n      return false;\n\n    // good\n    if (test) return false;\n\n    // good\n    if (test) {\n      return false;\n    }\n\n    // bad\n    function foo() { return false; }\n\n    // good\n    function bar() {\n      return false;\n    }\n    ```\n\n  \u003ca name=\"16.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"blocks--cuddled-elses\"\u003e\u003c/a\u003e\n  - [16.2](#blocks--cuddled-elses) `if` 表达式的 `else`和 `if` 的右大括号在一行。eslint: [`brace-style`](http://eslint.org/docs/rules/brace-style)\n\n    ```javascript\n    // bad\n    if (test) {\n      thing1();\n      thing2();\n    }\n    else {\n      thing3();\n    }\n\n    // good\n    if (test) {\n      thing1();\n      thing2();\n    } else {\n      thing3();\n    }\n    ```\n\n  \u003ca name=\"16.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"blocks--no-else-return\"\u003e\u003c/a\u003e\n\n  - [16.3](#blocks--no-else-return) 如果 `if` 语句中总是需要用 `return` 返回，那后续的 `else` 就不需要写了。 `if` 块中包含 `return`， 它后面的 `else if` 块中也包含了 `return`， 这个时候就可以把 `return` 分到多个 `if` 语句块中。 eslint: [`no-else-return`](https://eslint.org/docs/rules/no-else-return)\n\n    ```javascript\n    // bad\n    function foo() {\n      if (x) {\n        return x;\n      } else {\n        return y;\n      }\n    }\n\n    // bad\n    function cats() {\n      if (x) {\n        return x;\n      } else if (y) {\n        return y;\n      }\n    }\n\n    // bad\n    function dogs() {\n      if (x) {\n        return x;\n      } else {\n        if (y) {\n          return y;\n        }\n      }\n    }\n\n    // good\n    function foo() {\n      if (x) {\n        return x;\n      }\n\n      return y;\n    }\n\n    // good\n    function cats() {\n      if (x) {\n        return x;\n      }\n\n      if (y) {\n        return y;\n      }\n    }\n\n    // good\n    function dogs(x) {\n      if (x) {\n        if (z) {\n          return y;\n        }\n      } else {\n        return z;\n      }\n    }\n    ```\n\n**[⬆ 返回顶部](#目录)**\n\n## 控制语句\n\n  \u003ca name=\"17.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"control-statements\"\u003e\u003c/a\u003e\n  - [17.1](#control-statements) 当你的控制语句（`if`, `while` 等）太长或者超过最大长度限制的时候，把每一个（组）判断条件放在单独一行里。逻辑操作符放在行首。\n\n    \u003e 为什么？把逻辑操作符放在行首是让操作符的对齐方式和链式函数保持一致。这提高了可读性，也让复杂逻辑更清晰。\n\n    ```javascript\n    // bad\n    if ((foo === 123 || bar === 'abc') \u0026\u0026 doesItLookGoodWhenItBecomesThatLong() \u0026\u0026 isThisReallyHappening()) {\n      thing1();\n    }\n\n    // bad\n    if (foo === 123 \u0026\u0026\n      bar === 'abc') {\n      thing1();\n    }\n\n    // bad\n    if (foo === 123\n      \u0026\u0026 bar === 'abc') {\n      thing1();\n    }\n\n    // bad\n    if (\n      foo === 123 \u0026\u0026\n      bar === 'abc'\n    ) {\n      thing1();\n    }\n\n    // good\n    if (\n      foo === 123\n      \u0026\u0026 bar === 'abc'\n    ) {\n      thing1();\n    }\n\n    // good\n    if (\n      (foo === 123 || bar === 'abc')\n      \u0026\u0026 doesItLookGoodWhenItBecomesThatLong()\n      \u0026\u0026 isThisReallyHappening()\n    ) {\n      thing1();\n    }\n\n    // good\n    if (foo === 123 \u0026\u0026 bar === 'abc') {\n      thing1();\n    }\n    ```\n\n  \u003ca name=\"17.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"control-statement--value-selection\"\u003e\u003c/a\u003e\u003ca name=\"control-statements--value-selection\"\u003e\u003c/a\u003e\n  - [17.2](#control-statements--value-selection) 不要用选择操作符代替控制语句。\n\n    ```javascript\n    // bad\n    !isRunning \u0026\u0026 startRunning();\n\n    // good\n    if (!isRunning) {\n      startRunning();\n    }\n    ```\n\n**[⬆ 返回顶部](#目录)**\n\n## 注释\n\n  \u003ca name=\"18.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"comments--multiline\"\u003e\u003c/a\u003e\n  - [18.1](#comments--multiline) 多行注释用 `/** ... */`。\n\n    ```javascript\n    // bad\n    // make() returns a new element\n    // based on the passed in tag name\n    //\n    // @param {String} tag\n    // @return {Element} element\n    function make(tag) {\n\n      // ...\n\n      return element;\n    }\n\n    // good\n    /**\n     * make() returns a new element\n     * based on the passed-in tag name\n     */\n    function make(tag) {\n\n      // ...\n\n      return element;\n    }\n    ```\n\n  \u003ca name=\"18.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"comments--singleline\"\u003e\u003c/a\u003e\n  - [18.2](#comments--singleline) 单行注释用 `//`，将单行注释放在被注释区域上面。如果注释不是在第一行，那么注释前面就空一行。\n\n    ```javascript\n    // bad\n    const active = true;  // is current tab\n\n    // good\n    // is current tab\n    const active = true;\n\n    // bad\n    function getType() {\n      console.log('fetching type...');\n      // set the default type to 'no type'\n      const type = this._type || 'no type';\n\n      return type;\n    }\n\n    // good\n    function getType() {\n      console.log('fetching type...');\n\n      // set the default type to 'no type'\n      const type = this._type || 'no type';\n\n      return type;\n    }\n\n    // also good\n    function getType() {\n      // set the default type to 'no type'\n      const type = this._type || 'no type';\n\n      return type;\n    }\n    ```\n\n  \u003ca name=\"18.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"comments--spaces\"\u003e\u003c/a\u003e\n  - [18.3](#comments--spaces) 所有注释开头空一格，方便阅读。eslint: [`spaced-comment`](http://eslint.org/docs/rules/spaced-comment)\n\n    ```javascript\n    // bad\n    //is current tab\n    const active = true;\n\n    // good\n    // is current tab\n    const active = true;\n\n    // bad\n    /**\n     *make() returns a new element\n     *based on the passed-in tag name\n     */\n    function make(tag) {\n\n      // ...\n\n      return element;\n    }\n\n    // good\n    /**\n     * make() returns a new element\n     * based on the passed-in tag name\n     */\n    function make(tag) {\n\n      // ...\n\n      return element;\n    }\n    ```\n\n  \u003ca name=\"18.4\"\u003e\u003c/a\u003e\n  \u003ca name=\"comments--actionitems\"\u003e\u003c/a\u003e\n  - [18.4](#comments--actionitems) 在你的注释前使用 `FIXME` 或 `TODO` 前缀，这有助于其他开发人员快速理解你指出的需要修复的问题， 或者您建议需要实现的问题的解决方案。 这些不同于常规注释，它们是有明确含义的。`FIXME：需要修复这个问题`或`TODO：需要实现的功能`。\n\n  \u003ca name=\"18.5\"\u003e\u003c/a\u003e\n  \u003ca name=\"comments--fixme\"\u003e\u003c/a\u003e\n\n  - [18.5](#comments--fixme) 用 `// FIXME:` 给问题做注释。\n\n    ```javascript\n    class Calculator extends Abacus {\n      constructor() {\n        super();\n\n        // FIXME: shouldn't use a global here\n        total = 0;\n      }\n    }\n    ```\n\n  \u003ca name=\"18.6\"\u003e\u003c/a\u003e\n  \u003ca name=\"comments--todo\"\u003e\u003c/a\u003e\n  - [18.6](#comments--todo) 用 `// TODO:` 去注释问题的解决方案。\n\n    ```javascript\n    class Calculator extends Abacus {\n      constructor() {\n        super();\n\n        // TODO: total should be configurable by an options param\n        this.total = 0;\n      }\n    }\n    ```\n\n**[⬆ 返回顶部](#目录)**\n\n\n## 空格\n\n  \u003ca name=\"19.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--spaces\"\u003e\u003c/a\u003e\n\n  - [19.1](#whitespace--spaces) 一个缩进使用两个空格。eslint: [`indent`](http://eslint.org/docs/rules/indent)\n\n    ```javascript\n    // bad\n    function foo() {\n    ∙∙∙∙const name;\n    }\n\n    // bad\n    function bar() {\n    ∙const name;\n    }\n\n    // good\n    function baz() {\n    ∙∙const name;\n    }\n    ```\n\n  \u003ca name=\"19.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--before-blocks\"\u003e\u003c/a\u003e\n  - [19.2](#whitespace--before-blocks) 在大括号前空一格。eslint: [`space-before-blocks`](http://eslint.org/docs/rules/space-before-blocks)\n\n    ```javascript\n    // bad\n    function test(){\n      console.log('test');\n    }\n\n    // good\n    function test() {\n      console.log('test');\n    }\n\n    // bad\n    dog.set('attr',{\n      age: '1 year',\n      breed: 'Bernese Mountain Dog',\n    });\n\n    // good\n    dog.set('attr', {\n      age: '1 year',\n      breed: 'Bernese Mountain Dog',\n    });\n    ```\n\n  \u003ca name=\"19.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--around-keywords\"\u003e\u003c/a\u003e\n  - [19.3](#whitespace--around-keywords) 在控制语句（`if`, `while` 等）的圆括号前空一格。在函数调用和定义时，参数列表和函数名之间不空格。 eslint: [`keyword-spacing`](http://eslint.org/docs/rules/keyword-spacing)\n\n    ```javascript\n    // bad\n    if(isJedi) {\n      fight ();\n    }\n\n    // good\n    if (isJedi) {\n      fight();\n    }\n\n    // bad\n    function fight () {\n      console.log ('Swooosh!');\n    }\n\n    // good\n    function fight() {\n      console.log('Swooosh!');\n    }\n    ```\n\n  \u003ca name=\"19.4\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--infix-ops\"\u003e\u003c/a\u003e\n  - [19.4](#whitespace--infix-ops) 用空格来隔开运算符。eslint: [`space-infix-ops`](http://eslint.org/docs/rules/space-infix-ops)\n\n    ```javascript\n    // bad\n    const x=y+5;\n\n    // good\n    const x = y + 5;\n    ```\n\n  \u003ca name=\"19.5\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--newline-at-end\"\u003e\u003c/a\u003e\n  - [19.5](#whitespace--newline-at-end) 文件结尾空一行。eslint: [`eol-last`](https://eslint.org/docs/rules/eol-last)\n\n    ```javascript\n    // bad\n    import { es6 } from './AirbnbStyleGuide';\n      // ...\n    export default es6;\n    ```\n\n    ```javascript\n    // bad\n    import { es6 } from './AirbnbStyleGuide';\n      // ...\n    export default es6;\n\n    ```\n\n    ```javascript\n    // good\n    import { es6 } from './AirbnbStyleGuide';\n      // ...\n    export default es6;↵\n    ```\n\n  \u003ca name=\"19.6\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--chains\"\u003e\u003c/a\u003e\n\n  - [19.6](#whitespace--chains) 当出现长的方法链式调用时（\u003e2个）用缩进。用点开头强调该行是一个方法调用，而不是一个新的语句。eslint: [`newline-per-chained-call`](http://eslint.org/docs/rules/newline-per-chained-call) [`no-whitespace-before-property`](http://eslint.org/docs/rules/no-whitespace-before-property)\n\n    ```javascript\n    // bad\n    $('#items').find('.selected').highlight().end().find('.open').updateCount();\n\n    // bad\n    $('#items').\n      find('.selected').\n        highlight().\n        end().\n      find('.open').\n        updateCount();\n\n    // good\n    $('#items')\n      .find('.selected')\n        .highlight()\n        .end()\n      .find('.open')\n        .updateCount();\n\n    // bad\n    const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)\n        .attr('width', (radius + margin) * 2).append('svg:g')\n        .attr('transform', `translate(${radius + margin}, ${radius + margin})`)\n        .call(tron.led);\n\n    // good\n    const leds = stage.selectAll('.led')\n        .data(data)\n      .enter().append('svg:svg')\n        .classed('led', true)\n        .attr('width', (radius + margin) * 2)\n      .append('svg:g')\n        .attr('transform', `translate(${radius + margin}, ${radius + margin})`)\n        .call(tron.led);\n\n    // good\n    const leds = stage.selectAll('.led').data(data);\n    const svg = leds.enter().append('svg:svg');\n    svg.classed('led', true).attr('width', (radius + margin) * 2);\n    const g = svg.append('svg:g');\n    g.attr('transform', `translate(${radius + margin}, ${radius + margin})`).call(tron.led);\n    ```\n\n  \u003ca name=\"19.7\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--after-blocks\"\u003e\u003c/a\u003e\n  - [19.7](#whitespace--after-blocks) 在一个代码块后下一条语句前空一行。\n\n    ```javascript\n    // bad\n    if (foo) {\n      return bar;\n    }\n    return baz;\n\n    // good\n    if (foo) {\n      return bar;\n    }\n\n    return baz;\n\n    // bad\n    const obj = {\n      foo() {\n      },\n      bar() {\n      },\n    };\n    return obj;\n\n    // good\n    const obj = {\n      foo() {\n      },\n\n      bar() {\n      },\n    };\n\n    return obj;\n\n    // bad\n    const arr = [\n      function foo() {\n      },\n      function bar() {\n      },\n    ];\n    return arr;\n\n    // good\n    const arr = [\n      function foo() {\n      },\n\n      function bar() {\n      },\n    ];\n\n    return arr;\n    ```\n\n  \u003ca name=\"19.8\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--padded-blocks\"\u003e\u003c/a\u003e\n  - [19.8](#whitespace--padded-blocks) 不要用空白行填充块。eslint: [`padded-blocks`](http://eslint.org/docs/rules/padded-blocks)\n\n    ```javascript\n    // bad\n    function bar() {\n\n      console.log(foo);\n\n    }\n\n    // also bad\n    if (baz) {\n\n      console.log(quux);\n    } else {\n      console.log(foo);\n\n    }\n\n    // good\n    function bar() {\n      console.log(foo);\n    }\n\n    // good\n    if (baz) {\n      console.log(quux);\n    } else {\n      console.log(foo);\n    }\n    ```\n\n  \u003ca name=\"whitespace--no-multiple-blanks\"\u003e\u003c/a\u003e\n  - [19.9](#whitespace--no-multiple-blanks) 不要在代码之间使用多个空白行填充。eslint: [`no-multiple-empty-lines`](https://eslint.org/docs/rules/no-multiple-empty-lines)\n\n    \u003c!-- markdownlint-disable MD012 --\u003e\n    ```javascript\n    // bad\n    class Person {\n      constructor(fullName, email, birthday) {\n        this.fullName = fullName;\n\n\n        this.email = email;\n\n\n        this.setAge(birthday);\n      }\n\n\n      setAge(birthday) {\n        const today = new Date();\n\n\n        const age = this.getAge(today, birthday);\n\n\n        this.age = age;\n      }\n\n\n      getAge(today, birthday) {\n        // ..\n      }\n    }\n\n    // good\n    class Person {\n      constructor(fullName, email, birthday) {\n        this.fullName = fullName;\n        this.email = email;\n        this.setAge(birthday);\n      }\n\n      setAge(birthday) {\n        const today = new Date();\n        const age = getAge(today, birthday);\n        this.age = age;\n      }\n\n      getAge(today, birthday) {\n        // ..\n      }\n    }\n    ```\n\n  \u003ca name=\"19.10\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--in-parens\"\u003e\u003c/a\u003e\n\n  - [19.10](#whitespace--in-parens) 圆括号里不要加空格。eslint: [`space-in-parens`](http://eslint.org/docs/rules/space-in-parens)\n\n    ```javascript\n    // bad\n    function bar( foo ) {\n      return foo;\n    }\n\n    // good\n    function bar(foo) {\n      return foo;\n    }\n\n    // bad\n    if ( foo ) {\n      console.log(foo);\n    }\n\n    // good\n    if (foo) {\n      console.log(foo);\n    }\n    ```\n\n  \u003ca name=\"19.11\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--in-brackets\"\u003e\u003c/a\u003e\n  - [19.11](#whitespace--in-brackets) 方括号里不要加空格。 eslint: [`array-bracket-spacing`](http://eslint.org/docs/rules/array-bracket-spacing)\n\n    ```javascript\n    // bad\n    const foo = [ 1, 2, 3 ];\n    console.log(foo[ 0 ]);\n\n    // good，逗号分隔符后还是要空格的。\n    const foo = [1, 2, 3];\n    console.log(foo[0]);\n    ```\n\n  \u003ca name=\"19.12\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--in-braces\"\u003e\u003c/a\u003e\n  - [19.12](#whitespace--in-braces) 花括号里加空格 。eslint: [`object-curly-spacing`](http://eslint.org/docs/rules/object-curly-spacing)\n\n    ```javascript\n    // bad\n    const foo = {clark: 'kent'};\n\n    // good\n    const foo = { clark: 'kent' };\n    ```\n\n  \u003ca name=\"19.13\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--max-len\"\u003e\u003c/a\u003e\n\n  - [19.13](#whitespace--max-len) 避免一行代码超过100个字符（包含空格）。注意：对于 [上面](#strings--line-length)，长字符串不受此规则限制，不应换行。 eslint: [`max-len`](http://eslint.org/docs/rules/max-len)\n\n    \u003e 为什么？这样确保可读性和可维护性。\n\n    ```javascript\n    // bad\n    const foo = jsonData \u0026\u0026 jsonData.foo \u0026\u0026 jsonData.foo.bar \u0026\u0026 jsonData.foo.bar.baz \u0026\u0026 jsonData.foo.bar.baz.quux \u0026\u0026 jsonData.foo.bar.baz.quux.xyzzy;\n\n    // bad\n    $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() =\u003e console.log('Congratulations!')).fail(() =\u003e console.log('You have failed this city.'));\n\n    // good\n    const foo = jsonData\n      \u0026\u0026 jsonData.foo\n      \u0026\u0026 jsonData.foo.bar\n      \u0026\u0026 jsonData.foo.bar.baz\n      \u0026\u0026 jsonData.foo.bar.baz.quux\n      \u0026\u0026 jsonData.foo.bar.baz.quux.xyzzy;\n\n    // better\n    const foo = jsonData\n      ?.foo\n      ?.bar\n      ?.baz\n      ?.quux\n      ?.xyzzy;\n\n    // good\n    $.ajax({\n      method: 'POST',\n      url: 'https://airbnb.com/',\n      data: { name: 'John' },\n    })\n      .done(() =\u003e console.log('Congratulations!'))\n      .fail(() =\u003e console.log('You have failed this city.'));\n    ```\n\n  \u003ca name=\"19.14\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--block-spacing\"\u003e\u003c/a\u003e\n\n  - [19.14](#whitespace--block-spacing) 作为语句的花括号内也要加空格 —— `{` 后和 `}` 前都需要空格。 eslint: [`block-spacing`](https://eslint.org/docs/rules/block-spacing)\n\n    ```javascript\n    // bad\n    function foo() {return true;}\n    if (foo) { bar = 0;}\n\n    // good\n    function foo() { return true; }\n    if (foo) { bar = 0; }\n    ```\n\n  \u003ca name=\"19.15\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--comma-spacing\"\u003e\u003c/a\u003e\n  - [19.15](#whitespace--comma-spacing) `,` 前不要空格， `,` 后需要空格。 eslint: [`comma-spacing`](https://eslint.org/docs/rules/comma-spacing)\n\n    ```javascript\n    // bad\n    const foo = 1,bar = 2;\n    const arr = [1 , 2];\n\n    // good\n    const foo = 1, bar = 2;\n    const arr = [1, 2];\n    ```\n\n  \u003ca name=\"19.16\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--computed-property-spacing\"\u003e\u003c/a\u003e\n  - [19.16](#whitespace--computed-property-spacing) 花括号跟属性间要有空格，中括号跟属性间没有空格。 eslint: [`computed-property-spacing`](https://eslint.org/docs/rules/computed-property-spacing)\n\n    译者注：以代码为准。\n\n    ```javascript\n    // bad\n    obj[foo ]\n    obj[ 'foo']\n    const x = {[ b ]: a}\n    obj[foo[ bar ]]\n\n    // good\n    obj[foo]\n    obj['foo']\n    const x = { [b]: a }\n    obj[foo[bar]]\n    ```\n\n  \u003ca name=\"19.17\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--func-call-spacing\"\u003e\u003c/a\u003e\n  - [19.17](#whitespace--func-call-spacing) 调用函数时，函数名和小括号之间不要空格。 eslint: [`func-call-spacing`](https://eslint.org/docs/rules/func-call-spacing)\n\n    ```javascript\n    // bad\n    func ();\n\n    func\n    ();\n\n    // good\n    func();\n    ```\n\n  \u003ca name=\"19.18\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--key-spacing\"\u003e\u003c/a\u003e\n  - [19.18](#whitespace--key-spacing) 在对象的字面量属性中， `key`  和 `value` 之间要有空格。 eslint: [`key-spacing`](https://eslint.org/docs/rules/key-spacing)\n\n    ```javascript\n    // bad\n    const obj = { foo : 42 };\n    const obj2 = { foo:42 };\n\n    // good\n    const obj = { foo: 42 };\n    ```\n\n  \u003ca name=\"19.19\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--no-trailing-spaces\"\u003e\u003c/a\u003e\n\n  - [19.19](#whitespace--no-trailing-spaces) 行末不要空格。 eslint: [`no-trailing-spaces`](https://eslint.org/docs/rules/no-trailing-spaces)\n\n  \u003ca name=\"19.20\"\u003e\u003c/a\u003e\n  \u003ca name=\"whitespace--no-multiple-empty-lines\"\u003e\u003c/a\u003e\n\n  - [19.20](#whitespace--no-multiple-empty-lines) 避免出现多个空行。 在文件末尾只允许空一行。文件开始处不要出现空行。eslint: [`no-multiple-empty-lines`](https://eslint.org/docs/rules/no-multiple-empty-lines)\n\n    \u003c!-- markdownlint-disable MD012 --\u003e\n    ```javascript\n    // bad - multiple empty lines\n    const x = 1;\n\n\n    const y = 2;\n\n    // bad - 2+ newlines at end of file\n    const x = 1;\n    const y = 2;\n\n\n    // bad - 1+ newline(s) at beginning of file\n\n    const x = 1;\n    const y = 2;\n\n    // good\n    const x = 1;\n    const y = 2;\n\n    ```\n    \u003c!-- markdownlint-enable MD012 --\u003e\n\n**[⬆ 返回顶部](#目录)**\n\n## 逗号\n\n  \u003ca name=\"20.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"commas--leading-trailing\"\u003e\u003c/a\u003e\n  - [20.1](#commas--leading-trailing) 不要前置逗号。eslint: [`comma-style`](http://eslint.org/docs/rules/comma-style)\n\n    ```javascript\n    // bad\n    const story = [\n        once\n      , upon\n      , aTime\n    ];\n\n    // good\n    const story = [\n      once,\n      upon,\n      aTime,\n    ];\n\n    // bad\n    const hero = {\n        firstName: 'Ada'\n      , lastName: 'Lovelace'\n      , birthYear: 1815\n      , superPower: 'computers'\n    };\n\n    // good\n    const hero = {\n      firstName: 'Ada',\n      lastName: 'Lovelace',\n      birthYear: 1815,\n      superPower: 'computers',\n    };\n    ```\n\n  \u003ca name=\"20.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"commas--dangling\"\u003e\u003c/a\u003e\n\n  - [20.2](#commas--dangling) 额外结尾逗号: **要** eslint: [`comma-dangle`](http://eslint.org/docs/rules/comma-dangle)\n\n    \u003e 为什么？这使 git diffs 更简洁。此外，像Babel这样的转换器会删除转换代码中的额外的逗号，这意味着你不必担心旧版浏览器中的 [结尾逗号问题](https://github.com/airbnb/javascript/blob/es5-deprecated/es5/README.md#commas)。\n\n    ```diff\n    // bad - 没有结尾逗号的 git diff\n    const hero = {\n         firstName: 'Florence',\n    -    lastName: 'Nightingale'\n    +    lastName: 'Nightingale',\n    +    inventorOf: ['coxcomb chart', 'modern nursing']\n    };\n\n    // good - 有结尾逗号的 git diff\n    const hero = {\n         firstName: 'Florence',\n         lastName: 'Nightingale',\n    +    inventorOf: ['coxcomb chart', 'modern nursing'],\n    };\n    ```\n\n    ```javascript\n    // bad\n    const hero = {\n      firstName: 'Dana',\n      lastName: 'Scully'\n    };\n\n    const heroes = [\n      'Batman',\n      'Superman'\n    ];\n\n    // good\n    const hero = {\n      firstName: 'Dana',\n      lastName: 'Scully',\n    };\n\n    const heroes = [\n      'Batman',\n      'Superman',\n    ];\n\n    // bad\n    function createHero(\n      firstName,\n      lastName,\n      inventorOf\n    ) {\n      // does nothing\n    }\n\n    // good\n    function createHero(\n      firstName,\n      lastName,\n      inventorOf,\n    ) {\n      // does nothing\n    }\n\n    // good (注意，逗号不应出现在使用了 ... 操作符后的参数后面)\n    function createHero(\n      firstName,\n      lastName,\n      inventorOf,\n      ...heroArgs\n    ) {\n      // does nothing\n    }\n\n    // bad\n    createHero(\n      firstName,\n      lastName,\n      inventorOf\n    );\n\n    // good\n    createHero(\n      firstName,\n      lastName,\n      inventorOf,\n    );\n\n    // good  (注意，逗号不应出现在使用了 ... 操作符后的参数后面)\n    createHero(\n      firstName,\n      lastName,\n      inventorOf,\n      ...heroArgs\n    )\n    ```\n\n**[⬆ 返回顶部](#目录)**\n\n\n## 分号\n\n  \u003ca name=\"21.1\"\u003e\u003c/a\u003e\n  - [21.1](#21.1) **要分号！** eslint: [`semi`](http://eslint.org/docs/rules/semi)\n\n    \u003e 为什么？当 JavaScript 遇到没有分号结尾的一行，它会执行 [自动插入分号](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion) 这一规则来决定行末是否加分号。如果 JavaScript 在你的断行里错误的插入了分号，就会出现一些古怪的行为。当新的功能加到JavaScript 里后， 这些规则会变得更复杂难懂。清晰的结束语句，并通过配置代码检查去检查没有带分号的地方可以帮助你防止这种错误。\n\n    ```javascript\n    // bad - 抛出异常\n    const luke = {}\n    const leia = {}\n    [luke, leia].forEach((jedi) =\u003e jedi.father = 'vader')\n\n    // bad - 抛出异常\n    const reaction = 'No! That’s impossible!'\n    (async function meanwhileOnTheFalcon() {\n      // 处理 `leia`, `lando`, `chewie`, `r2`, `c3p0`\n      // ...\n    }())\n\n    // bad - 将返回 `undefined` 而不是下一行的值。由于 ASI，当 `return`单独出现在一行时，这种情况会一直出现。\n    function foo() {\n      return\n        'search your feelings, you know it to be foo'\n    }\n\n    // good\n    const luke = {};\n    const leia = {};\n    [luke, leia].forEach((jedi) =\u003e {\n      jedi.father = 'vader';\n    });\n\n    // good\n    const reaction = \"No! That’s impossible!\";\n    (async function meanwhileOnTheFalcon() {\n      // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`\n      // ...\n    }());\n\n    // good\n    function foo() {\n      return 'search your feelings, you know it to be foo';\n    }\n    ```\n\n    [更多](https://stackoverflow.com/questions/7365172/semicolon-before-self-invoking-function/7365214%237365214).\n\n**[⬆ 返回顶部](#目录)**\n\n\n## 类型转换与强制转换\n\n  \u003ca name=\"22.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"coercion--explicit\"\u003e\u003c/a\u003e\n  - [22.1](#coercion--explicit) 在语句开始执行强制类型转换。\n\n  \u003ca name=\"22.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"coercion--strings\"\u003e\u003c/a\u003e\n\n  - [22.2](#coercion--strings)  字符串: eslint: [`no-new-wrappers`](https://eslint.org/docs/rules/no-new-wrappers)\n\n    ```javascript\n    // =\u003e this.reviewScore = 9;\n\n    // bad\n    const totalScore = new String(this.reviewScore); // typeof totalScore is \"object\" not \"string\"\n\n    // bad\n    const totalScore = this.reviewScore + ''; // 将会执行 this.reviewScore.valueOf()\n\n    // bad\n    const totalScore = this.reviewScore.toString(); // 不保证返回 string\n\n    // good\n    const totalScore = String(this.reviewScore);\n    ```\n\n  \u003ca name=\"22.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"coercion--numbers\"\u003e\u003c/a\u003e\n\n  - [22.3](#coercion--numbers) 数字: 用 `Number` 做类型转换，`parseInt` 转换 `string` 应总是带上基数。 eslint: [`radix`](http://eslint.org/docs/rules/radix)\n\n    \u003e 为什么？函数 `parseInt`  会根据指定的基数将字符串转换为数字。字符串开头的空白字符将会被忽略，如果参数基数（第二个参数）为 `undefined` 或者 `0` ，除非字符串开头为 `0x` 或 `0X`（十六进制），会默认假设为 `10`。这个差异来自 ECMAScript 3，它不鼓励（但是允许）解释八进制。在 2013 年之前，一些实现不兼容这种行为。因为我们需要支持旧浏览器，所以应当始终指定进制。\n\n    \u003e 译者注：翻译的可能不是很好，总之使用 `parseInt()` 时始终指定进制数（第二个参数）就可以了。\n\n    ```javascript\n    const inputValue = '4';\n\n    // bad\n    const val = new Number(inputValue);\n\n    // bad\n    const val = +inputValue;\n\n    // bad\n    const val = inputValue \u003e\u003e 0;\n\n    // bad\n    const val = parseInt(inputValue);\n\n    // good\n    const val = Number(inputValue);\n\n    // good\n    const val = parseInt(inputValue, 10);\n    ```\n\n  \u003ca name=\"22.4\"\u003e\u003c/a\u003e\n  \u003ca name=\"coercion--comment-deviations\"\u003e\u003c/a\u003e\n  - [22.4](#coercion--comment-deviations) 请在注释中解释为什么要用移位运算和你在做什么。无论你做什么狂野的事，比如由于 `parseInt` 是你的性能瓶颈导致你一定要用移位运算。说明这个是因为 [性能原因](https://jsperf.com/coercion-vs-casting/3)。\n\n    ```javascript\n    // good\n    /**\n     * parseInt 是代码运行慢的原因\n     * 用 Bitshifting 将字符串转成数字使代码运行效率大幅提升\n     */\n    const val = inputValue \u003e\u003e 0;\n    ```\n\n  \u003ca name=\"22.5\"\u003e\u003c/a\u003e\n  \u003ca name=\"coercion--bitwise\"\u003e\u003c/a\u003e\n\n  - [22.5](#coercion--bitwise) **注意:** 用移位运算要小心。数字是用 [64-位](https://es5.github.io/#x4.3.19)表示的，但移位运算常常返回的是32为整形[source](https://es5.github.io/#x11.7))。移位运算对大于 32 位的整数会导致意外行为。[Discussion](https://github.com/airbnb/javascript/issues/109). 最大的 32 位整数是 2,147,483,647:\n\n    ```javascript\n    2147483647 \u003e\u003e 0 //=\u003e 2147483647\n    2147483648 \u003e\u003e 0 //=\u003e -2147483648\n    2147483649 \u003e\u003e 0 //=\u003e -2147483647\n    ```\n\n  \u003ca name=\"22.6\"\u003e\u003c/a\u003e\n  \u003ca name=\"coercion--booleans\"\u003e\u003c/a\u003e\n  - [22.6](#coercion--booleans) 布尔: eslint: [`no-new-wrappers`](https://eslint.org/docs/rules/no-new-wrappers)\n\n    ```javascript\n    const age = 0;\n\n    // bad\n    const hasAge = new Boolean(age);\n\n    // good\n    const hasAge = Boolean(age);\n\n    // best\n    const hasAge = !!age;\n    ```\n\n**[⬆ 返回顶部](#目录)**\n\n\n## 命名规范\n\n  \u003ca name=\"23.1\"\u003e\u003c/a\u003e\n  \u003ca name=\"naming--descriptive\"\u003e\u003c/a\u003e\n  - [23.1](#naming--descriptive) 避免用一个字母命名，让你的命名有意义。eslint: [`id-length`](http://eslint.org/docs/rules/id-length)\n\n    ```javascript\n    // bad\n    function q() {\n      // ...\n    }\n\n    // good\n    function query() {\n      // ...\n    }\n    ```\n\n  \u003ca name=\"23.2\"\u003e\u003c/a\u003e\n  \u003ca name=\"naming--camelCase\"\u003e\u003c/a\u003e\n  - [23.2](#naming--camelCase) 用小驼峰命名法来命名你的对象、函数、实例。eslint: [`camelcase`](http://eslint.org/docs/rules/camelcase)\n\n    ```javascript\n    // bad\n    const OBJEcttsssss = {};\n    const this_is_my_object = {};\n    function c() {}\n\n    // good\n    const thisIsMyObject = {};\n    function thisIsMyFunction() {}\n    ```\n\n  \u003ca name=\"23.3\"\u003e\u003c/a\u003e\n  \u003ca name=\"naming--PascalCase\"\u003e\u003c/a\u003e\n  - [23.3](#naming--PascalCase) 用大驼峰命名法来命名类。eslint: [`new-cap`](http://eslint.org/docs/rules/new-cap)\n\n    ```javascript\n    // bad\n    function user(options) {\n      this.name = options.name;\n    }\n\n    const bad = new user({\n      name: 'nope',\n    });\n\n    // good\n    class User {\n      constructor(options) {\n        this.name = options.name;\n      }\n    }\n\n    const good = new User({\n      name: 'yup',\n    });\n    ```\n\n  \u003ca name=\"23.4\"\u003e\u003c/a\u003e\n  \u003ca name=\"naming--leading-underscore\"\u003e\u003c/a\u003e\n  - [23.4](#naming--leading-underscore) 不要用前置或后置下划线。eslint: [`no-underscore-dangle`](http://eslint.org/docs/rules/no-underscore-dangle)\n\n    \u003e 为什么？JavaScript 没有私有属性或私有方法的概念。尽管前置下划线通常的概念上意味着私有，事实上，这些属性是完全公有的，因此这部分也是你的 API 的内容。这一概念可能会导致开发者误以为更改这个不会导致崩溃或者不需要测试。如果你想要什么东西变成私有，那就不要让它在这里出现。\n\n    ```javascript\n    // 不好的\n    this.__firstName__ = 'Panda';\n    this.firstName_ = 'Panda';\n    this._firstName = 'Panda';\n\n    // 好的\n    this.firstName = 'Panda';\n\n    // 好的， 在支持 WeakMaps 环境中可用\n    // 见 https://compat-table.github.io/compat-table/es6/#test-WeakMap\n    const firstNames = new WeakMap();\n    firstNames.set(this, 'Panda');\n    ```\n\n  \u003ca name=\"23.5\"\u003e\u003c/a\u003e\n  \u003ca name=\"naming--self-this\"\u003e\u003c/a\u003e\n  - [23.5](#naming--self-this) 不要保存引用 `this`，用箭头函数或 [函数绑定——Function#bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)。\n\n    ```javascript\n    // bad\n    function foo() {\n      const self = this;\n      return function () {\n        console.log(self);\n      };\n    }\n\n    // bad\n    function foo() {\n      const that = this;\n      return function () {\n        console.log(that);\n      };\n    }\n\n    // good\n    function foo() {\n      return () =\u003e {\n        console.log(this);\n      };\n    }\n    ```\n\n  \u003ca name=\"23.6\"\u003e\u003c/a\u003e\n  \u003ca name=\"naming--filename-matches-export\"\u003e\u003c/a\u003e\n\n  - [23.6](#naming--filename-matches-export) `export default` 导出模块A，则这个文件名也叫 `A.*`， `import` 时候的参数也叫 `A`。 大小写完全一致。\n\n    ```javascript\n    // file 1 contents\n    class CheckBox {\n      // ...\n    }\n    export default CheckBox;\n\n    // file 2 contents\n    export default function fortyTwo() { return 42; }\n\n    // file 3 contents\n    export default function insideDirectory() {}\n\n    // in some other file\n    // bad\n    import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename\n    import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export\n    import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export\n\n    // bad\n    import CheckBox from './check_box'; // PascalCase import/export, snake_case filename\n    import forty_two from './forty_two'; // snake_case import/filename, camelCase export\n    import inside_directory from './inside_directory'; // snake_case import, camelCase export\n    import index from './inside_directory/index'; // requiring the index file explicitly\n    import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly\n\n    // good\n    import CheckBox from './CheckBox'; // PascalCase export/import/filename\n    import fortyTwo from './fortyTwo'; // camelCase export/import/filename\n    import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit \"index\"\n    // ^ supports both insideDirectory.js and insideDirectory/index.js\n    ```\n\n  \u003ca name=\"23.7\"\u003e\u003c/a\u003e\n  \u003ca name=\"naming--camelCase-default-export\"\u003e\u003c/a\u003e\n  - [23.7](#naming--camelCase-default-export) 当你 export-default 一个函数时，函数名用小驼峰，文件名需要和函数名一致。\n\n    ```javascript\n    function makeStyleGuide() {\n      // ...\n    }\n\n    export default makeStyleGuide;\n    ```\n\n  \u003ca name=\"23.8\"\u003e\u003c/a\u003e\n  \u003ca name=\"naming--PascalCase-singleton\"\u003e\u003c/a\u003e\n\n  - [23.8](#naming--PascalCase-singleton) 当你 export 一个结构体/类/单例/函数库/对象 时用大驼峰。\n\n    ```javascript\n    const AirbnbStyleGuide = {\n      es6: {\n      }\n    };\n\n    export default AirbnbStyleGuide;\n    ```\n\n  \u003ca name=\"23.9\"\u003e\u003c/a\u003e\n  \u003ca name=\"naming--Acronyms-and-Initialisms\"\u003e\u003c/a\u003e\n  - [23.9](#naming--Acronyms-and-Initialisms) 简称和缩写应该全部大写或全部小写。\n\n    \u003e 为什么？名字都是给人读的，不是为了去适应计算机算法。\n\n    ```javascript\n    // bad\n    import SmsContainer from './containers/SmsContainer';\n\n    // bad\n    const HttpRequests = [\n      // ...","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flin-123%2Fjavascript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flin-123%2Fjavascript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flin-123%2Fjavascript/lists"}