diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000000..cdf21d6822
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,103 @@
+
+// JS 书写规范
+// http://eslint.org
+// http://standardjs.com/rules.html
+// - 规范文档参看[javascript-style-guide](https://github.com/webcoding/javascript-style-guide/blob/master/docs)
+// - 具体配置及注意事项参看 [config-eslint.md](https://github.com/webcoding/javascript-style-guide/blob/master/docs/config-eslint.md)
+
+// NOTE: 兼容性设定,放置在项目根目录,此文件同时支持 ES5、ES6 便于切换(切换注释即可,待修订)
+
+module.exports = {
+ root: true,
+ parser: 'babel-eslint',
+ installedESLint: true,
+ parserOptions: {
+ ecmaVersion: 8,
+ sourceType: 'module',
+ "ecmaFeatures": {
+ "jsx": true,
+ // lambda表达式
+ "arrowFunctions": true,
+ // 块级作用域,允许使用let const
+ "blockBindings": true,
+ // class
+ "classes": true,
+ // http://es6.ruanyifeng.com/#docs/function#函数参数的默认值
+ "defaultParams": true,
+ // 解构赋值
+ "destructuring": true,
+ // http://es6.ruanyifeng.com/#docs/object#对象的扩展运算符
+ "experimentalObjectRestSpread": true,
+ // http://es6.ruanyifeng.com/#docs/iterator#for---of循环
+ "forOf": true,
+ // http://es6.ruanyifeng.com/#docs/generator
+ "generators": true,
+ // 允许使用模块,模块内默认严格模式
+ "modules": true,
+ // 允许字面量定义对象时,用表达式做属性名
+ // http://es6.ruanyifeng.com/#docs/object#属性名表达式
+ "objectLiteralComputedProperties": true,
+ // 允许对象字面量方法名简写
+ /*var o = {
+ method() {
+ return "Hello!";
+ }
+ };
+
+ 等同于
+
+ var o = {
+ method: function() {
+ return "Hello!";
+ }
+ };
+ */
+ "objectLiteralShorthandMethods": true,
+ /*
+ 对象字面量属性名简写
+ var foo = "bar";
+ var baz = {foo};
+ baz // {foo: "bar"}
+
+ // 等同于
+ var baz = {foo: foo};
+ */
+ "objectLiteralShorthandProperties": true,
+ // http://es6.ruanyifeng.com/#docs/function#rest参数
+ "restParams": true,
+ // http://es6.ruanyifeng.com/#docs/function#扩展运算符
+ "spread": true,
+ "superInFunctions": true,
+ // http://es6.ruanyifeng.com/#docs/string#模板字符串
+ "templateStrings": true,
+ "unicodeCodePointEscapes": true,
+ },
+ },
+ globals: {
+ Vue: false,
+ },
+
+ plugins: [
+ // 处理 html 文件内 js 代码规范等
+ 'html',
+ ],
+
+ // ES5 推荐规范
+ // extends: 'webcoding/configurations/airbnb/es5',
+ // ES6 推荐规范
+ extends: 'airbnb',
+ // extends: 'webcoding/configurations/airbnb/es6',
+
+ // add your custom rules here
+ rules: {
+ // 行尾分号,默认配置always,要求在行末加上分号,standard 配置强制不带
+ semi: ['error', 'never'],
+ // 多行模式必须带逗号,单行模式不能带逗号
+ 'comma-dangle': ['error', 'always-multiline'],
+ 'max-len': ['error', {'code': 160}],
+ // 禁止使用 console debugger
+ // 'no-console': 1,
+ // 禁止使用 debugger
+ // 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
+ },
+}
diff --git a/README.md b/README.md
index 6e6c2d8eaa..aaf653a092 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,11 @@
# Airbnb JavaScript Style Guide() {
+- [ES6 中文版](https://github.com/webcoding/javascript-style-guide/blob/master/docs/es6_zh-cn_v3.md)
+- [ES5 中文版](https://github.com/webcoding/javascript-style-guide/blob/master/docs/es5_zh-cn_v3.md)
+- [eslint 配置注意事项](https://github.com/webcoding/javascript-style-guide/blob/master/docs/config-eslint.md)
+
+目前代码规范只整理了写法建议,还有一些实现层面需要保持的原则,如:单一职责原则 (SRP)、开放封装原则(OCP)、里氏替换原则(LSP)、接口隔离原则(ISP)、依赖倒置原则(DIP) 等等,还有很多这样的实现案例及原则,正在整理中...
+
*A mostly reasonable approach to JavaScript*
[](https://www.npmjs.com/package/eslint-config-airbnb)
diff --git a/docs/.eslintignore b/docs/.eslintignore
new file mode 100644
index 0000000000..6f5d4184fb
--- /dev/null
+++ b/docs/.eslintignore
@@ -0,0 +1,8 @@
+# /node_modules/* and /bower_components/* ignored by default
+
+# Ignore built files except build/index.js
+build/*
+!build/build-test.js
+
+**/vendor/*.js
+dist/
diff --git a/docs/clean-code-javascript.md b/docs/clean-code-javascript.md
new file mode 100644
index 0000000000..df93f8ed08
--- /dev/null
+++ b/docs/clean-code-javascript.md
@@ -0,0 +1,2111 @@
+
+# JavaScript 代码整洁之道
+
+> 本文转载自:[众成翻译](http://www.zcfy.cc)
+> 译者:[边城](http://www.zcfy.cc/@jamesfancy)
+> 链接:[http://www.zcfy.cc/article/2273](http://www.zcfy.cc/article/2273)
+> 原文:[https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md](https://github.com/ryanmcdermott/clean-code-javascript/blob/master/README.md)
+
+其他 https://github.com/cmstead/js-refactor
+
+
+# [](#clean-code-javascript) JavaScript 代码整洁之道
+
+
+## [](#table-of-contents)目录
+
+1. [概述](#introduction)
+1. [变量](#variables)
+1. [函数](#functions)
+1. [对象和数据结构](#objects-and-data-structures)
+1. [类](#classes)
+1. [测试](#testing)
+1. [并发](#concurrency)
+1. [错误处理](#error-handling)
+1. [格式](#formatting)
+1. [注释](#comments)
+
+
+## [](#introduction)概述
+
+[](http://p0.qhimg.com/t01cb6a971284a41620.jpg)
+
+Robert C. Martin 在
+[_《代码整洁之道》_](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882) 中提到的软件工程原则,同样适用于 JavaScript。这不是一个风格参考。它指导如何用 JavaScript 编写可读、可复用、可重构的软件。
+
+并不是每一个原则都必须严格遵循,甚至很少得到大家的认同。它们仅用于参考,不过要知道这些原则都是_《代码整洁之道》_的作者们累积多年的集体经验。
+
+我们在软件工程方面的技术发展刚刚超过 50 年,我们仍然在学习很多东西。当软件架构和架构本身一样古老的时候,我们应该遵循更为严格规则。现在,对于你和你的团队编写的 JavaScript 代码,不妨依据这些准则来进行质量评估。
+
+还有一件事:知道这些不会马上让你成为更好的软件开发者,在工作中常年使用这些准则不能让你避免错误。每一段代码都从最初的草图开始到最终成型,就像为湿粘土塑形一样。最后,当我们与同行一起审查的时候,再把不完美的地方消除掉。不要因为初稿需要改善而否定自己,需要要否定的只是那些代码!
+
+
+## [](#variables)**变量**
+
+
+### [](#use-meaningful-and-pronounceable-variable-names)使用有准确意义的变量名
+
+```javascript
+// bad
+var yyyymmdstr = moment().format('YYYY/MM/DD');
+```
+
+```javascript
+// good
+var yearMonthDay = moment().format('YYYY/MM/DD');
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#use-es6-constants-when-variable-values-do-not-change)在变量的值不会改变时使用 ES6 的常量
+
+在不好的示例中,变量可以被改变。如果你申明一个常量,它会在整个程序中始终保持不变。
+
+```javascript
+// bad
+var FIRST_US_PRESIDENT = "George Washington";
+```
+
+```javascript
+// good
+const FIRST_US_PRESIDENT = "George Washington";
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#use-the-same-vocabulary-for-the-same-type-of-variable)对同一类型的变量使用相同的词汇
+
+```javascript
+// bad
+getUserInfo();
+getClientData();
+getCustomerRecord();
+```
+
+```javascript
+// good
+getUser();
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#use-searchable-names)使用可检索的名称
+
+我们阅读的代码永远比写的折。写可读性强、易于检索的的代码非常重要。在程序中使用_无_明确意义的变量名会难以理解,对读者造成伤害。所以,把名称定义成可检索的。
+
+```javascript
+// bad
+// 见鬼,525600 是个啥?
+for (var i = 0; i < 525600; i++) {
+ runCronJob();
+}```
+
+```javascript
+// good
+// 用 `var` 申明为大写的全局变量
+var MINUTES_IN_A_YEAR = 525600;
+for (var i = 0; i < MINUTES_IN_A_YEAR; i++) {
+ runCronJob();
+}```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#use-explanatory-variables)使用解释性的变量
+
+```javascript
+// bad
+const cityStateRegex = /^(.+)[,\\s]+(.+?)\s*(\d{5})?$/;
+saveCityState(cityStateRegex.match(cityStateRegex)[1], cityStateRegex.match(cityStateRegex)[2]);
+```
+
+```javascript
+// good
+const cityStateRegex = /^(.+)[,\\s]+(.+?)\s*(\d{5})?$/;
+const match = cityStateRegex.match(cityStateRegex)
+const city = match[1];
+const state = match[2];
+saveCityState(city, state);
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#avoid-mental-mapping)避免暗示
+
+显式优于隐式。
+
+```javascript
+// bad
+var locations = ['Austin', 'New York', 'San Francisco'];
+locations.forEach((l) => {
+ doStuff();
+ doSomeOtherStuff();
+ ...
+ ...
+ ...
+ // 等等,`l` 又是什么?
+ dispatch(l);
+});
+```
+
+```javascript
+// good
+var locations = ['Austin', 'New York', 'San Francisco'];
+locations.forEach((location) => {
+ doStuff();
+ doSomeOtherStuff();
+ ...
+ ...
+ ...
+ dispatch(location);
+});
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#dont-add-unneeded-context)不要添加没必要的上下文
+
+如果你的类名称/对象名称已经说明了它们是什么,不要在(属性)变量名里重复。
+
+```javascript
+// bad
+var Car = {
+ carMake: 'Honda',
+ carModel: 'Accord',
+ carColor: 'Blue'
+};
+
+function paintCar(car) {
+ car.carColor = 'Red';
+}
+```
+
+```javascript
+// good
+var Car = {
+ make: 'Honda',
+ model: 'Accord',
+ color: 'Blue'
+};
+
+function paintCar(car) {
+ car.color = 'Red';
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#short-circuiting-is-cleaner-than-conditionals)短路语法比条件语句更清晰
+
+```javascript
+// bad
+function createMicrobrewery(name) {
+ var breweryName;
+ if (name) {
+ breweryName = name;
+ } else {
+ breweryName = 'Hipster Brew Co.';
+ }
+}
+```
+
+```javascript
+// good
+function createMicrobrewery(name) {
+ var breweryName = name || 'Hipster Brew Co.'
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## [](#functions)**函数**
+
+
+### [](#function-arguments-2-or-less-ideally)函数参数 (理论上少于等于2个)
+
+限制函数参数的数量极为重要,它会让你更容易测试函数。超过3个参数会导致组合膨胀,以致于你必须根据不同的参数对大量不同的情况进行测试。
+
+理想情况下是没有参数。有一个或者两个参数也还好,三个就应该避免了。多于那个数量就应该考虑合并。通常情况下,如果你有多于2个参数,你的函数会尝试做太多事情。如果不是这样,大多数时候可以使用一个高阶对象作为参数使用。
+
+既然 JavaScript 允许我们在运行时随意创建对象,而不需要预先定义样板,那么你在需要很多参数的时候就可以使用一个对象来处理。
+
+```javascript
+// bad
+function createMenu(title, body, buttonText, cancellable) {
+ ...
+}
+```
+
+```javascript
+// good
+var menuConfig = {
+ title: 'Foo',
+ body: 'Bar',
+ buttonText: 'Baz',
+ cancellable: true
+}
+
+function createMenu(menuConfig) {
+ ...
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#functions-should-do-one-thing)一个函数只做一件事
+
+目前这是软件工程中最重要的原则。如果函数做了较多的事情,它就难以组合、测试和推测。当你让函数只做一件事情的时候,它们就很容易重构,而且代码读起来也会清晰得多。你只需要遵循本指南的这一条,就能领先于其他很多开发者。
+
+```javascript
+// bad
+function emailClients(clients) {
+ clients.forEach(client => {
+ let clientRecord = database.lookup(client);
+ if (clientRecord.isActive()) {
+ email(client);
+ }
+ });
+}
+```
+
+```javascript
+// good
+function emailClients(clients) {
+ clients.forEach(client => {
+ emailClientIfNeeded(client);
+ });
+}
+
+function emailClientIfNeeded(client) {
+ if (isClientActive(client)) {
+ email(client);
+ }
+}
+
+function isClientActive(client) {
+ let clientRecord = database.lookup(client);
+ return clientRecord.isActive();
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#function-names-should-say-what-they-do)函数名称要说明它做的事
+
+```javascript
+// bad
+function dateAdd(date, month) {
+ // ...
+}
+
+let date = new Date();
+
+// 很难从函数名了解到加了什么
+dateAdd(date, 1);
+```
+
+```javascript
+// good
+function dateAddMonth(date, month) {
+ // ...
+}
+
+let date = new Date();
+dateAddMonth(date, 1);
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#functions-should-only-be-one-level-of-abstraction)函数应该只抽象一个层次
+
+如果你有多个层次的抽象,那么你的函数通常做了太多事情,此时应该拆分函数使其易于复用和易于测试。
+
+```javascript
+// bad
+function parseBetterJSAlternative(code) {
+ let REGEXES = [
+ // ...
+ ];
+
+ let statements = code.split(' ');
+ let tokens;
+ REGEXES.forEach((REGEX) => {
+ statements.forEach((statement) => {
+ // ...
+ })
+ });
+
+ let ast;
+ tokens.forEach((token) => {
+ // lex...
+ });
+
+ ast.forEach((node) => {
+ // parse...
+ })
+}
+```
+
+```javascript
+// good
+function tokenize(code) {
+ let REGEXES = [
+ // ...
+ ];
+
+ let statements = code.split(' ');
+ let tokens;
+ REGEXES.forEach((REGEX) => {
+ statements.forEach((statement) => {
+ // ...
+ })
+ });
+
+ return tokens;
+}
+
+function lexer(tokens) {
+ let ast;
+ tokens.forEach((token) => {
+ // lex...
+ });
+
+ return ast;
+}
+
+function parseBetterJSAlternative(code) {
+ let tokens = tokenize(code);
+ let ast = lexer(tokens);
+ ast.forEach((node) => {
+ // parse...
+ })
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#remove-duplicate-code)删除重复代码
+
+任何情况下,都不要有重复的代码。没有任何原因,它很可能是阻碍你成为专业开发者的最糟糕的一件事。重复代码意味着你要修改某些逻辑的时候要修改不止一个地方的代码。JavaScript 是弱类型语句,所以它很容易写通用性强的函数。记得利用这一点!
+
+```javascript
+// bad
+function showDeveloperList(developers) {
+ developers.forEach(developers => {
+ var expectedSalary = developer.calculateExpectedSalary();
+ var experience = developer.getExperience();
+ var githubLink = developer.getGithubLink();
+ var data = {
+ expectedSalary: expectedSalary,
+ experience: experience,
+ githubLink: githubLink
+ };
+
+ render(data);
+ });
+}
+
+function showManagerList(managers) {
+ managers.forEach(manager => {
+ var expectedSalary = manager.calculateExpectedSalary();
+ var experience = manager.getExperience();
+ var portfolio = manager.getMBAProjects();
+ var data = {
+ expectedSalary: expectedSalary,
+ experience: experience,
+ portfolio: portfolio
+ };
+
+ render(data);
+ });
+}
+```
+
+```javascript
+// good
+function showList(employees) {
+ employees.forEach(employee => {
+ var expectedSalary = employee.calculateExpectedSalary();
+ var experience = employee.getExperience();
+ var portfolio;
+
+ if (employee.type === 'manager') {
+ portfolio = employee.getMBAProjects();
+ } else {
+ portfolio = employee.getGithubLink();
+ }
+
+ var data = {
+ expectedSalary: expectedSalary,
+ experience: experience,
+ portfolio: portfolio
+ };
+
+ render(data);
+ });
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#use-default-arguments-instead-of-short-circuiting)使用默认参数代替短路表达式
+
+```javascript
+// bad
+function writeForumComment(subject, body) {
+ subject = subject || 'No Subject';
+ body = body || 'No text';
+}
+```
+
+```javascript
+// good
+function writeForumComment(subject = 'No subject', body = 'No text') {
+ ...
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#set-default-objects-with-objectassign)用 Object.assign 设置默认对象
+
+```javascript
+// bad
+var menuConfig = {
+ title: null,
+ body: 'Bar',
+ buttonText: null,
+ cancellable: true
+}
+
+function createMenu(config) {
+ config.title = config.title || 'Foo'
+ config.body = config.body || 'Bar'
+ config.buttonText = config.buttonText || 'Baz'
+ config.cancellable = config.cancellable === undefined ? config.cancellable : true;
+
+}
+
+createMenu(menuConfig);
+```
+
+```javascript
+// good
+var menuConfig = {
+ title: 'Order',
+ // User did not include 'body' key
+ buttonText: 'Send',
+ cancellable: true
+}
+
+function createMenu(config) {
+ config = Object.assign({
+ title: 'Foo',
+ body: 'Bar',
+ buttonText: 'Baz',
+ cancellable: true
+ }, config);
+
+ // 现在 config 等于: {title: "Foo", body: "Bar", buttonText: "Baz", cancellable: true}
+ // ...
+}
+
+createMenu(menuConfig);
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#dont-use-flags-as-function-parameters)不要把标记用作函数参数
+
+标记告诉你的用户这个函数做的事情不止一件。但是函数应该只做一件事。如果你的函数中会根据某个布尔参数产生不同的分支,那就拆分这个函数。
+
+```javascript
+// bad
+function createFile(name, temp) {
+ if (temp) {
+ fs.create('./temp/' + name);
+ } else {
+ fs.create(name);
+ }
+}
+```
+
+```javascript
+// good
+function createTempFile(name) {
+ fs.create('./temp/' + name);
+}
+
+function createFile(name) {
+ fs.create(name);
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#avoid-side-effects)避免副作用
+
+如果一个函数不是获取一个输入的值并返回其它值,它就有可能产生副作用。这些副作用可能是写入文件、修改一些全局变量,或者意外地把你所有钱转给一个陌生人。
+
+现在你确实需要在程序中有副作用。像前面提到的那样,你可能需要写入文件。现在你需要做的事情是搞清楚在哪里集中完成这件事情。不要使用几个函数或类来完成写入某个特定文件的工作。采用一个,就一个服务来完成。
+
+关键点是避免觉的陷阱,比如在没有结构的对象间共享状态,使用可以被任意修改的易变的数据类型,没有集中处理发生的副作用等。如果你能做到,你就能比其他大多数程序员更愉快。
+
+```javascript
+// bad
+// 下面的函数使用了全局变量。
+// 如果有另一个函数在使用 name,现在可能会因为 name 变成了数组而不能正常运行。
+var name = 'Ryan McDermott';
+
+function splitIntoFirstAndLastName() {
+ name = name.split(' ');
+}
+
+splitIntoFirstAndLastName();
+
+console.log(name); // ['Ryan', 'McDermott'];
+```
+
+```javascript
+// good
+function splitIntoFirstAndLastName(name) {
+ return name.split(' ');
+}
+
+var name = 'Ryan McDermott'
+var newName = splitIntoFirstAndLastName(name);
+
+console.log(name); // 'Ryan McDermott';
+console.log(newName); // ['Ryan', 'McDermott'];
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#dont-write-to-global-functions)不要写入全局函数
+
+JavaScript 中全局污染是一件糟糕的事情,因为它可能和另外库发生冲突,然而使用你 API 的用户却不会知道——直到他们在生产中遇到一个异常。来思考一个例子:你想扩展 JavaScript 的原生 Array,使之拥有一个 `diff` 方法,用来展示两数据之前的区别,这时你会怎么做?你可以给 `Array.prototype` 添加一个新的函数,但它可能会与其它想做同样事情的库发生冲突。如果那个库实现的 `diff` 只是比如数组中第一个元素和最后一个元素的异同会发生什么事情呢?这就是为什么最好是使用 ES6 的类语法从全局的 `Array` 派生一个类来做这件事。
+
+```javascript
+// bad
+Array.prototype.diff = function(comparisonArray) {
+ var values = [];
+ var hash = {};
+
+ for (var i of comparisonArray) {
+ hash[i] = true;
+ }
+
+ for (var i of this) {
+ if (!hash[i]) {
+ values.push(i);
+ }
+ }
+
+ return values;
+}
+```
+
+```javascript
+// good
+class SuperArray extends Array {
+ constructor(...args) {
+ super(...args);
+ }
+
+ diff(comparisonArray) {
+ var values = [];
+ var hash = {};
+
+ for (var i of comparisonArray) {
+ hash[i] = true;
+ }
+
+ for (var i of this) {
+ if (!hash[i]) {
+ values.push(i);
+ }
+ }
+
+ return values;
+ }
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#favor-functional-programming-over-imperative-programming)喜欢上命令式编程之上的函数式编程
+
+如果 Haskell 是 IPA 那么 JavaScript 就是 O'Douls。就是说,与 Haskell 不同,JavaScript 不是函数式编程语言,不过它仍然有一点函数式的意味。函数式语言更整洁也更容易测试,所以你最好能喜欢上这种编程风格。
+
+```javascript
+// bad
+const programmerOutput = [
+ {
+ name: 'Uncle Bobby',
+ linesOfCode: 500
+ }, {
+ name: 'Suzie Q',
+ linesOfCode: 1500
+ }, {
+ name: 'Jimmy Gosling',
+ linesOfCode: 150
+ }, {
+ name: 'Gracie Hopper',
+ linesOfCode: 1000
+ }
+];
+
+var totalOutput = 0;
+
+for (var i = 0; i < programmerOutput.length; i++) {
+ totalOutput += programmerOutput[i].linesOfCode;
+}
+```
+
+```javascript
+// good
+const programmerOutput = [
+ {
+ name: 'Uncle Bobby',
+ linesOfCode: 500
+ }, {
+ name: 'Suzie Q',
+ linesOfCode: 1500
+ }, {
+ name: 'Jimmy Gosling',
+ linesOfCode: 150
+ }, {
+ name: 'Gracie Hopper',
+ linesOfCode: 1000
+ }
+];
+
+var totalOutput = programmerOutput
+ .map((programmer) => programmer.linesOfCode)
+ .reduce((acc, linesOfCode) => acc + linesOfCode, 0);
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#encapsulate-conditionals)封装条件
+
+```javascript
+// bad
+if (fsm.state === 'fetching' && isEmpty(listNode)) {
+ /// ...
+}
+```
+
+```javascript
+// good
+function shouldShowSpinner(fsm, listNode) {
+ return fsm.state === 'fetching' && isEmpty(listNode);
+}
+
+if (shouldShowSpinner(fsmInstance, listNodeInstance)) {
+ // ...
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#avoid-negative-conditionals)避免否定条件
+
+```javascript
+// bad
+function isDOMNodeNotPresent(node) {
+ // ...
+}
+
+if (!isDOMNodeNotPresent(node)) {
+ // ...
+}
+```
+
+```javascript
+// good
+function isDOMNodePresent(node) {
+ // ...
+}
+
+if (isDOMNodePresent(node)) {
+ // ...
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#avoid-conditionals)避免条件
+
+这似乎是个不可能完成的任务。大多数人第一次听到这个的时候会说,“没有 `if` 语句我该怎么办?”回答是在多数情况下都可以使用多态来实现相同的任务。第二个问题通常是,“那太好了,不过我为什么要这么做呢?”答案在于我们之前了解过整洁的概念:一个函数应该只做一件事情。如果你的类和函数有 `if` 语句,就意味着你的函数做了更多的事。记住,只做一件事。
+
+```javascript
+// bad
+class Airplane {
+ //...
+ getCruisingAltitude() {
+ switch (this.type) {
+ case '777':
+ return getMaxAltitude() - getPassengerCount();
+ case 'Air Force One':
+ return getMaxAltitude();
+ case 'Cessna':
+ return getMaxAltitude() - getFuelExpenditure();
+ }
+ }
+}
+```
+
+```javascript
+// good
+class Airplane {
+ //...
+}
+
+class Boeing777 extends Airplane {
+ //...
+ getCruisingAltitude() {
+ return getMaxAltitude() - getPassengerCount();
+ }
+}
+
+class AirForceOne extends Airplane {
+ //...
+ getCruisingAltitude() {
+ return getMaxAltitude();
+ }
+}
+
+class Cessna extends Airplane {
+ //...
+ getCruisingAltitude() {
+ return getMaxAltitude() - getFuelExpenditure();
+ }
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#avoid-type-checking-part-1)避免类型检查(第1部分)
+
+JavaScript 是无类型的,也就是说函数可以获取任意类型的参数。有时候你会觉得这种自由是种折磨,因而会不由自主地在函数中使用类型检查。有很多种方法可以避免类型检查。首先要考虑的就是 API 的一致性。
+
+```javascript
+// bad
+function travelToTexas(vehicle) {
+ if (vehicle instanceof Bicycle) {
+ vehicle.peddle(this.currentLocation, new Location('texas'));
+ } else if (vehicle instanceof Car) {
+ vehicle.drive(this.currentLocation, new Location('texas'));
+ }
+}
+```
+
+```javascript
+// good
+function travelToTexas(vehicle) {
+ vehicle.move(this.currentLocation, new Location('texas'));
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#avoid-type-checking-part-2)避免类型检查(第2部分)
+
+如果你在处理基本类型的数据,比如字符串,整数和数组,又不能使用多态,这时你会觉得需要使用类型检查,那么可以考虑 TypeScript。这是普通 JavaScript 的完美替代品,它在标准的 JavaScript 语法之上提供了静态类型。普通 JavaScript 手工检查类型的问题在于这样会写很多废话,而人为的“类型安全”并不能弥补损失的可读性。让你的 JavaScript 保持整洁,写很好的测试,并保持良好的代码审查。否则让 TypeScript (我说过,这是很好的替代品)来做所有事情。
+
+```javascript
+// bad
+function combine(val1, val2) {
+ if (typeof val1 == "number" && typeof val2 == "number" ||
+ typeof val1 == "string" && typeof val2 == "string") {
+ return val1 + val2;
+ } else {
+ throw new Error('Must be of type String or Number');
+ }
+}
+```
+
+```javascript
+// good
+function combine(val1, val2) {
+ return val1 + val2;
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#dont-over-optimize)不要过度优化
+
+现在浏览器在运行时悄悄地做了很多优化工作。很多时候你的优化都是在浪费时间。[这里有很好的资源](https://github.com/petkaantonov/bluebird/wiki/Optimization-killers) 可以看看哪些优化比较缺乏。把它们作为目标,直到他们能固定下来的时候。
+
+```javascript
+// bad
+// 在旧浏览器中,每次循环的成本都比较高,因为每次都会重算 `len`。
+// 现在浏览器中,这已经被优化了。
+for (var i = 0, len = list.length; i < len; i++) {
+ // ...
+}
+```
+
+```javascript
+// good
+for (var i = 0; i < list.length; i++) {
+ // ...
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#remove-dead-code)删除不用的代码
+
+不用的代码和重复的代码一样糟糕。在代码库中保留无用的代码是毫无道理的事情。如果某段代码用不到,那就删掉它!如果你以后需要它,仍然可以从代码库的历史版本中找出来。
+
+```javascript
+// bad
+function oldRequestModule(url) {
+ // ...
+}
+
+function newRequestModule(url) {
+ // ...
+}
+
+var req = newRequestModule;
+inventoryTracker('apples', req, 'www.inventory-awesome.io');
+```
+
+```javascript
+// good
+function newRequestModule(url) {
+ // ...
+}
+
+var req = newRequestModule;
+inventoryTracker('apples', req, 'www.inventory-awesome.io');
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## [](#objects-and-data-structures)**对象和数据结构**
+
+
+### [](#use-getters-and-setters)使用 getter 和 setter
+
+JavaScript 没有接口或者类型,也没有像 `public` 和 `private` 这样的关键字,所以很难应用设计模式。实事上,在对象上使用 getter 和 setter 访问数据远好于直接查找对象属性。“为什么?”你可能会这样问。那好,下面列出了原因:
+
+1. 你想在获取对象属性的时候做更多的事,不必在代码中寻找所有访问的代码来逐个修改。
+1. 在进行 `set` 的时候可以进行额外的数据检验。
+1. 封装内部表现。
+1. 在获取或设置的时候易于添加日志和错误处理。
+1. 继承当前类,可以重写默认功能。
+1. 可以对对象属性进行懒加载,比如说从服务器获取属性的数据。
+
+```javascript
+// bad
+class BankAccount {
+ constructor() {
+ this.balance = 1000;
+ }
+}
+
+let bankAccount = new BankAccount();
+
+// 买鞋...
+bankAccount.balance = bankAccount.balance - 100;
+```
+
+```javascript
+// good
+class BankAccount {
+ constructor() {
+ this.balance = 1000;
+ }
+
+ // It doesn't have to be prefixed with `get` or `set` to be a getter/setter
+ withdraw(amount) {
+ if (verifyAmountCanBeDeducted(amount)) {
+ this.balance -= amount;
+ }
+ }
+}
+
+let bankAccount = new BankAccount();
+
+// 买鞋...
+bankAccount.withdraw(100);
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#make-objects-have-private-members)让对象拥有私有成员
+
+这可以通过闭包实现(ES5以之前的版本)。
+
+```javascript
+// bad
+var Employee = function(name) {
+ this.name = name;
+}
+
+Employee.prototype.getName = function() {
+ return this.name;
+}
+
+var employee = new Employee('John Doe');
+console.log('Employee name: ' + employee.getName()); // Employee name: John Doe
+delete employee.name;
+console.log('Employee name: ' + employee.getName()); // Employee name: undefined
+```
+
+```javascript
+// good
+var Employee = (function() {
+ function Employee(name) {
+ this.getName = function() {
+ return name;
+ };
+ }
+
+ return Employee;
+}());
+
+var employee = new Employee('John Doe');
+console.log('Employee name: ' + employee.getName()); // Employee name: John Doe
+delete employee.name;
+console.log('Employee name: ' + employee.getName()); // Employee name: John Doe
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+
+## [](#classes)**类**
+
+
+### [](#single-responsibility-principle-srp)单一职责原则 (SRP)
+
+正如《代码整洁之道》所说,“不应该有超过一个原因来改变类”。往一个类里塞进许多功能是件诱人的事情,就像在坐飞机的时候只带一个手提箱一样。这带来的问题是,你的类不会在概念上有凝聚力,会有很多因素造成对它的改变。让你的类需要改变的次数最少是件非常重要的事情。这是因为如果一个类里塞入了太多功能,你只修改它的一部分,可能会让人难以理解它为何会影响代码库中其它相关模块。
+
+```javascript
+// bad
+class UserSettings {
+ constructor(user) {
+ this.user = user;
+ }
+
+ changeSettings(settings) {
+ if (this.verifyCredentials(user)) {
+ // ...
+ }
+ }
+
+ verifyCredentials(user) {
+ // ...
+ }
+}
+```
+
+```javascript
+// good
+class UserAuth {
+ constructor(user) {
+ this.user = user;
+ }
+
+ verifyCredentials() {
+ // ...
+ }
+}
+
+class UserSettings {
+ constructor(user) {
+ this.user = user;
+ this.auth = new UserAuth(user)
+ }
+
+ changeSettings(settings) {
+ if (this.auth.verifyCredentials()) {
+ // ...
+ }
+ }
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#openclosed-principle-ocp)开放封装原则(OCP)
+
+正如 Bertrand Meyer 所说,“软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。”这是什么意思呢?这个原则基本上规定了你应该允许用户扩展你的模块,但不需要打开 `.js` 源代码文件来进行编辑。
+
+```javascript
+// bad
+class AjaxRequester {
+ constructor() {
+ // 如果我们需要另一个 HTTP 方法,比如 DELETE,该怎么办?
+ // 我们必须打开这个文件然后手工把它加进去
+ this.HTTP_METHODS = ['POST', 'PUT', 'GET'];
+ }
+
+ get(url) {
+ // ...
+ }
+
+}
+```
+
+```javascript
+// good
+class AjaxRequester {
+ constructor() {
+ this.HTTP_METHODS = ['POST', 'PUT', 'GET'];
+ }
+
+ get(url) {
+ // ...
+ }
+
+ addHTTPMethod(method) {
+ this.HTTP_METHODS.push(method);
+ }
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#liskov-substitution-principle-lsp)里氏替换原则(LSP)
+
+这是一个吓人的术语,但描述的却是个简单的概念。它的正式定义为“如果 S 是 T 的子类,那所有 T 类型的对象都可以替换为 S 类型的对象(即 S 类型的对象可以替代 T 类型的对象),这个替换不会改变程序的任何性质(正确性、任务执行等)。”这确实是个吓人的定义。
+
+对此最好的解释是,如果你有父类和子类,那么父类和子类可以交替使用而不会造成不正确的结果。这可能仍然让人感到疑惑,那么让我们看看经典的正方形和矩形的例子。在数学上,正方形也是矩形,但是如果你在模型中通过继承使用 “is-a” 关系,你很快就会陷入困境。
+
+```javascript
+// bad
+class Rectangle {
+ constructor() {
+ this.width = 0;
+ this.height = 0;
+ }
+
+ setColor(color) {
+ // ...
+ }
+
+ render(area) {
+ // ...
+ }
+
+ setWidth(width) {
+ this.width = width;
+ }
+
+ setHeight(height) {
+ this.height = height;
+ }
+
+ getArea() {
+ return this.width * this.height;
+ }
+}
+
+class Square extends Rectangle {
+ constructor() {
+ super();
+ }
+
+ setWidth(width) {
+ this.width = width;
+ this.height = width;
+ }
+
+ setHeight(height) {
+ this.width = height;
+ this.height = height;
+ }
+}
+
+function renderLargeRectangles(rectangles) {
+ rectangles.forEach((rectangle) => {
+ rectangle.setWidth(4);
+ rectangle.setHeight(5);
+ let area = rectangle.getArea(); // 不好:这里对正方形会返回 25,但应该是 20.
+ rectangle.render(area);
+ })
+}
+
+let rectangles = [new Rectangle(), new Rectangle(), new Square()];
+renderLargeRectangles(rectangles);
+```
+
+```javascript
+// good
+class Shape {
+ constructor() {}
+
+ setColor(color) {
+ // ...
+ }
+
+ render(area) {
+ // ...
+ }
+}
+
+class Rectangle extends Shape {
+ constructor() {
+ super();
+ this.width = 0;
+ this.height = 0;
+ }
+
+ setWidth(width) {
+ this.width = width;
+ }
+
+ setHeight(height) {
+ this.height = height;
+ }
+
+ getArea() {
+ return this.width * this.height;
+ }
+}
+
+class Square extends Shape {
+ constructor() {
+ super();
+ this.length = 0;
+ }
+
+ setLength(length) {
+ this.length = length;
+ }
+
+ getArea() {
+ return this.length * this.length;
+ }
+}
+
+function renderLargeShapes(shapes) {
+ shapes.forEach((shape) => {
+ switch (shape.constructor.name) {
+ case 'Square':
+ shape.setLength(5);
+ case 'Rectangle':
+ shape.setWidth(4);
+ shape.setHeight(5);
+ }
+
+ let area = shape.getArea();
+ shape.render(area);
+ })
+}
+
+let shapes = [new Rectangle(), new Rectangle(), new Square()];
+renderLargeShapes(shapes);
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#interface-segregation-principle-isp)接口隔离原则(ISP)
+
+JavaScript 中没有接口,所以实行这个原则不能像其它语言那样严格。然而即使对 JavaScript 的弱类型系统来说,它仍然是重要的相关。
+
+ISP 指出,“客户不应该依赖于那些他们不使用的接口。” 由于 Duck Typing 理论,接口在 JavaScript 中是个隐性契约。
+
+在 JavaScript 中有一个很好的例子来演示这个原则,即一个拥有巨大设置对象的类。比较好的做法是不要求客户设置大量的选项,因为多数时候他们不需要所有设置。让这些选项成为可选的有助于防止“胖接口”。
+
+```javascript
+// bad
+class DOMTraverser {
+ constructor(settings) {
+ this.settings = settings;
+ this.setup();
+ }
+
+ setup() {
+ this.rootNode = this.settings.rootNode;
+ this.animationModule.setup();
+ }
+
+ traverse() {
+ // ...
+ }
+}
+
+let $ = new DOMTraverser({
+ rootNode: document.getElementsByTagName('body'),
+ animationModule: function() {} // 多数时候我们不需要动画
+ // ...
+});
+```
+
+```javascript
+// good
+class DOMTraverser {
+ constructor(settings) {
+ this.settings = settings;
+ this.options = settings.options;
+ this.setup();
+ }
+
+ setup() {
+ this.rootNode = this.settings.rootNode;
+ this.setupOptions();
+ }
+
+ setupOptions() {
+ if (this.options.animationModule) {
+ // ...
+ }
+ }
+
+ traverse() {
+ // ...
+ }
+}
+
+let $ = new DOMTraverser({
+ rootNode: document.getElementsByTagName('body'),
+ options: {
+ animationModule: function() {}
+ }
+});
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#dependency-inversion-principle-dip)依赖倒置原则(DIP)
+
+这个原则说明了两个基本问题:
+
+1\. 上层模块不应该依赖下层模块,两者都应该依赖抽象。
+
+2\. 抽象不应该依赖于具体实现,具体实现应该依赖于抽象。
+
+这一开始可能很难理解,但是如果你使用 Angular.js,你已经看到了对这个原则的一种实现形式:依赖注入(DI)。虽然它们不是完全相同的概念,DIP 阻止上层模块去了解下层模块的细节并设置它们。它可以通过 DI 来实现。这带来的巨大好处降低了模块间的耦合。耦合是种非常不好的开发模式,因为它让代码难以重构。
+
+前提已经提到,JavaScript 没有接口,因此抽象依赖于隐性契约。也就是说,一个对象/类会把方法和属性暴露给另一个对象/类。在下面的例子中,隐性契约是任何用于 `InventoryTracker` 的 Request 模块都应该拥有 `requestItems` 方法。
+
+```javascript
+// bad
+class InventoryTracker {
+ constructor(items) {
+ this.items = items;
+
+ // 不好:我们创建了一个依赖于特定请求的实现。
+ // 我们应该只依赖请求方法:`request` 的 requestItems
+ this.requester = new InventoryRequester();
+ }
+
+ requestItems() {
+ this.items.forEach((item) => {
+ this.requester.requestItem(item);
+ });
+ }
+}
+
+class InventoryRequester {
+ constructor() {
+ this.REQ_METHODS = ['HTTP'];
+ }
+
+ requestItem(item) {
+ // ...
+ }
+}
+
+let inventoryTracker = new InventoryTracker(['apples', 'bananas']);
+inventoryTracker.requestItems();
+```
+
+```javascript
+// good
+class InventoryTracker {
+ constructor(items, requester) {
+ this.items = items;
+ this.requester = requester;
+ }
+
+ requestItems() {
+ this.items.forEach((item) => {
+ this.requester.requestItem(item);
+ });
+ }
+}
+
+class InventoryRequesterV1 {
+ constructor() {
+ this.REQ_METHODS = ['HTTP'];
+ }
+
+ requestItem(item) {
+ // ...
+ }
+}
+
+class InventoryRequesterV2 {
+ constructor() {
+ this.REQ_METHODS = ['WS'];
+ }
+
+ requestItem(item) {
+ // ...
+ }
+}
+
+// 通过构建外部依赖并注入它们,我们很容易把请求模块替换成
+// 一个使用 WebSocket 的新模块。
+let inventoryTracker = new InventoryTracker(['apples', 'bananas'], new InventoryRequesterV2());
+inventoryTracker.requestItems();
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#prefer-es6-classes-over-es5-plain-functions)多用 ES6 类语法,少用 ES5 构造函数语法
+
+在经典的 ES5 的类定义中,很难找到易读的继承、构造、方法定义等。如果你需要继承(你会发现做不到),那就应该使用类语法。不过,应该尽可能使用小函数而不是类,直到你需要更大更复杂的对象。
+
+```javascript
+// bad
+var Animal = function(age) {
+ if (!(this instanceof Animal)) {
+ throw new Error("Instantiate Animal with `new`");
+ }
+
+ this.age = age;
+};
+
+Animal.prototype.move = function() {};
+
+var Mammal = function(age, furColor) {
+ if (!(this instanceof Mammal)) {
+ throw new Error("Instantiate Mammal with `new`");
+ }
+
+ Animal.call(this, age);
+ this.furColor = furColor;
+};
+
+Mammal.prototype = Object.create(Animal.prototype);
+Mammal.prototype.constructor = Mammal;
+Mammal.prototype.liveBirth = function() {};
+
+var Human = function(age, furColor, languageSpoken) {
+ if (!(this instanceof Human)) {
+ throw new Error("Instantiate Human with `new`");
+ }
+
+ Mammal.call(this, age, furColor);
+ this.languageSpoken = languageSpoken;
+};
+
+Human.prototype = Object.create(Mammal.prototype);
+Human.prototype.constructor = Human;
+Human.prototype.speak = function() {};
+```
+
+```javascript
+// good
+class Animal {
+ constructor(age) {
+ this.age = age;
+ }
+
+ move() {}
+}
+
+class Mammal extends Animal {
+ constructor(age, furColor) {
+ super(age);
+ this.furColor = furColor;
+ }
+
+ liveBirth() {}
+}
+
+class Human extends Mammal {
+ constructor(age, furColor, languageSpoken) {
+ super(age, furColor);
+ this.languageSpoken = languageSpoken;
+ }
+
+ speak() {}
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#use-method-chaining)使用方法链
+
+在这里我的意见与《代码整洁之道》的观点不同。有人认为方法链不整洁,而且违反了[得墨忒耳定律](https://en.wikipedia.org/wiki/Law_of_Demeter)。也许他们是对的,但这个模式在 JavaScript 中非常有用,你可以很多库中看到,比如 jQuery 和 Lodash。它让代码变得既简洁又有表现力。在类中,只需要在每个函数结束前返回 `this`,就实现了链式调用的类方法。
+
+```javascript
+// bad
+class Car {
+ constructor() {
+ this.make = 'Honda';
+ this.model = 'Accord';
+ this.color = 'white';
+ }
+
+ setMake(make) {
+ this.name = name;
+ }
+
+ setModel(model) {
+ this.model = model;
+ }
+
+ setColor(color) {
+ this.color = color;
+ }
+
+ save() {
+ console.log(this.make, this.model, this.color);
+ }
+}
+
+let car = new Car();
+car.setColor('pink');
+car.setMake('Ford');
+car.setModel('F-150')
+car.save();
+```
+
+```javascript
+// good
+class Car {
+ constructor() {
+ this.make = 'Honda';
+ this.model = 'Accord';
+ this.color = 'white';
+ }
+
+ setMake(make) {
+ this.name = name;
+ // NOTE: 返回 this 以实现链式调用
+ return this;
+ }
+
+ setModel(model) {
+ this.model = model;
+ // NOTE: 返回 this 以实现链式调用
+ return this;
+ }
+
+ setColor(color) {
+ this.color = color;
+ // NOTE: 返回 this 以实现链式调用
+ return this;
+ }
+
+ save() {
+ console.log(this.make, this.model, this.color);
+ }
+}
+
+let car = new Car()
+ .setColor('pink')
+ .setMake('Ford')
+ .setModel('F-150')
+ .save();
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#prefer-composition-over-inheritance)多用组合,少用继承
+
+大家都知道 GoF 的[_设计模式_](https://en.wikipedia.org/wiki/Design_Patterns),其中提到应该多用组合而不是继承。对于继承和组合,都有大量的理由在支撑,但这个准则的要点在于,你的想法本能地会想到继承,但这时候不防多思考一下用组合是否能更好的处理问题——某些时候,的确能。
+
+你可能会考虑:“我什么时候该用继承?”这取决于你遇到的问题。这里有一个不错的清单说明了什么时候用继承比用组合更合适:
+
+1. 你的继承是一个“is-a”关系,而不是“has-a”关系(Animal->Human 对比 User->UserDetails)。
+2. 可以从基础复用代码 (人可以像所有动物一样移动)。
+3. 你想通过修改基础来实现对所有子类的全局性更改。(改变动物移动时的热量消耗)。
+
+```javascript
+// bad
+class Employee {
+ constructor(name, email) {
+ this.name = name;
+ this.email = email;
+ }
+
+ // ...
+}
+
+// 这样不好,因为 Employees "拥有" 税务数据。EmployeeTaxData 不是属于 Employee 的一个类型
+class EmployeeTaxData extends Employee {
+ constructor(ssn, salary) {
+ super();
+ this.ssn = ssn;
+ this.salary = salary;
+ }
+
+ // ...
+}
+```
+
+```javascript
+// good
+class Employee {
+ constructor(name, email) {
+ this.name = name;
+ this.email = email;
+
+ }
+
+ setTaxData(ssn, salary) {
+ this.taxData = new EmployeeTaxData(ssn, salary);
+ }
+ // ...
+}
+
+class EmployeeTaxData {
+ constructor(ssn, salary) {
+ this.ssn = ssn;
+ this.salary = salary;
+ }
+
+ // ...
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## [](#testing)**测试**
+
+测试比生产更重要。如果你不进行测试,或者测试的量不够,那你就不能肯定你写的代码不会造成破坏。测试数量依靠你的开发团队来决定,但 100% 覆盖率(所有语句和分支)能让你拥有巨大的信心,也能使程序员们安心。也就是说,你需要一个不错的测试框架,还需要一个[好的覆盖检查工具](http://gotwarlost.github.io/istanbul/).
+
+没有什么理由可以让你不写测试。这里有 [大量不错的 JS 测试框架](http://jstherightway.org/#testing-tools),可以去找个你们团队喜欢的来用。如果你找一个适合在你的团队中使用的工作,就把为每个新产生的特性/方法添加测试作为目标。如果你喜欢测试驱动开发(TDD)的方法,非常好,但要注意在让你的测试覆盖所有特性,或者重构过的代码。
+
+
+### [](#single-concept-per-test)每次测试一个概念
+
+```javascript
+// bad
+const assert = require('assert');
+
+describe('MakeMomentJSGreatAgain', function() {
+ it('handles date boundaries', function() {
+ let date;
+
+ date = new MakeMomentJSGreatAgain('1/1/2015');
+ date.addDays(30);
+ date.shouldEqual('1/31/2015');
+
+ date = new MakeMomentJSGreatAgain('2/1/2016');
+ date.addDays(28);
+ assert.equal('02/29/2016', date);
+
+ date = new MakeMomentJSGreatAgain('2/1/2015');
+ date.addDays(28);
+ assert.equal('03/01/2015', date);
+ });
+});
+```
+
+```javascript
+// good
+const assert = require('assert');
+
+describe('MakeMomentJSGreatAgain', function() {
+ it('handles 30-day months', function() {
+ let date = new MakeMomentJSGreatAgain('1/1/2015');
+ date.addDays(30);
+ date.shouldEqual('1/31/2015');
+ });
+
+ it('handles leap year', function() {
+ let date = new MakeMomentJSGreatAgain('2/1/2016');
+ date.addDays(28);
+ assert.equal('02/29/2016', date);
+ });
+
+ it('handles non-leap year', function() {
+ let date = new MakeMomentJSGreatAgain('2/1/2015');
+ date.addDays(28);
+ assert.equal('03/01/2015', date);
+ });
+});
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## [](#concurrency)**Concurrency**
+
+
+### [](#use-promises-not-callbacks)使用 Promise 而不是回调
+
+回调并不整洁,它会导致过多的嵌套。ES6 的 Promise 是个内置的全局类型。使用它!
+
+```javascript
+// bad
+require('request').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin', function(err, response) {
+ if (err) {
+ console.error(err);
+ }
+ else {
+ require('fs').writeFile('article.html', response.body, function(err) {
+ if (err) {
+ console.error(err);
+ } else {
+ console.log('File written');
+ }
+ })
+ }
+})
+```
+
+```javascript
+// good
+require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin')
+ .then(function(response) {
+ return require('fs-promise').writeFile('article.html', response);
+ })
+ .then(function() {
+ console.log('File written');
+ })
+ .catch(function(err) {
+ console.error(err);
+ })
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#asyncawait-are-even-cleaner-than-promises)async/await 比 Promise 还整洁
+
+与回调相当,Promise 已经相当整洁了,但 ES7 带来了更整洁的解决方案 —— async 和 await。你要做的事情就是在一个函数前加上 `async` 关键字,然后写下命令形式的逻辑,而不再需要 `then` 链。现在可以使用这个 ES7 特性带来的便利!
+
+```javascript
+// bad
+require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin')
+ .then(function(response) {
+ return require('fs-promise').writeFile('article.html', response);
+ })
+ .then(function() {
+ console.log('File written');
+ })
+ .catch(function(err) {
+ console.error(err);
+ })
+```
+
+```javascript
+// good
+async function getCleanCodeArticle() {
+ try {
+ var request = await require('request-promise')
+ var response = await request.get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin');
+ var fileHandle = await require('fs-promise');
+
+ await fileHandle.writeFile('article.html', response);
+ console.log('File written');
+ } catch(err) {
+ console.log(err);
+ }
+ }
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## [](#error-handling)**错误处理**
+
+抛出错误是件好事!这表示运行时已经成功检测到程序出错了,它停止当前调用框上的函数执行,并中止进程(在 Node 中),最后在控制台通知你,并输出栈跟踪信息。
+
+
+### [](#dont-ignore-caught-errors)不要忽略捕捉到的错误
+
+捕捉到错误却什么也不错,你就失去了纠正错误的机会。多数情况下把错误记录到控制台(`console.log`)也不比忽略它好多少,因为在少量的控制台信息中很难发现这一条。如果尝试在 `try/catch` 中封装代码,就意味着你知道这里可能发生错,你应该在错误发生的时候有应对的计划、或者处理办法。
+
+```javascript
+// bad
+try {
+ functionThatMightThrow();
+} catch (error) {
+ console.log(error);
+}
+```
+
+```javascript
+// good
+try {
+ functionThatMightThrow();
+} catch (error) {
+ // 选择之一(比 console.log 更闹心):
+ console.error(error);
+ // 另一个选择:
+ notifyUserOfError(error);
+ // 另一个选择:
+ reportErrorToService(error);
+ // 或者所有上述三种选择!
+}
+```
+
+### [](#dont-ignore-rejected-promises)不要忽视被拒绝的Promise
+
+这一条与不要忽略从 `try/catch` 捕捉到的错误有相同的原因。
+
+```javascript
+// bad
+getdata()
+.then(data => {
+ functionThatMightThrow(data);
+})
+.catch(error => {
+ console.log(error);
+});
+```
+
+```javascript
+// good
+getdata()
+.then(data => {
+ functionThatMightThrow(data);
+})
+.catch(error => {
+ // 选择之一(比 console.log 更闹心):
+ console.error(error);
+ // 另一个选择:
+ notifyUserOfError(error);
+ // 另一个选择:
+ reportErrorToService(error);
+ // 或者所有上述三种选择!
+});
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## [](#formatting)**格式**
+
+格式是个很主观的东西,像这里提到的许多规则一,你不必完全遵循。要点**不在于争论**格式。[大量工具](http://standardjs.com/rules.html) 可以自动处理优化格式。用一个!让工程师争论格式问题简直就是在浪费时间和金钱。
+
+对于那些不能自动处理的格式(可以自动处理的包括缩进、Tab或空格、双引号或单引用等),就看看这里的指导。
+
+
+### [](#use-consistent-capitalization)使用一致的大小写
+
+JavaScript 是无类型的,所以大小写可以帮助你了解变量、函数等。这些规则具有较强的主观性,所以你的团队应该选择需要的。重点不在于你选择了什么,而在于要始终保持一致。
+
+```javascript
+// bad
+var DAYS_IN_WEEK = 7;
+var daysInMonth = 30;
+
+var songs = ['Back In Black', 'Stairway to Heaven', 'Hey Jude'];
+var Artists = ['ACDC', 'Led Zeppelin', 'The Beatles'];
+
+function eraseDatabase() {}
+function restore_database() {}
+
+class animal {}
+class Alpaca {}
+```
+
+```javascript
+// good
+var DAYS_IN_WEEK = 7;
+var DAYS_IN_MONTH = 30;
+
+var songs = ['Back In Black', 'Stairway to Heaven', 'Hey Jude'];
+var artists = ['ACDC', 'Led Zeppelin', 'The Beatles'];
+
+function eraseDatabase() {}
+function restoreDatabase() {}
+
+class Animal {}
+class Alpaca {}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#function-callers-and-callees-should-be-close)函数调用者和被调用者应该尽可能放在一起
+
+如果一个函数调用另一个函数,那应该让他们在源文件中的位置非常接近。理想情况下应该把调用者放在被调用者的正上方,这会让你的代码更易读,因为我们都习惯从上往下读代码,就像读报纸那样。
+
+```javascript
+// bad
+class PerformanceReview {
+ constructor(employee) {
+ this.employee = employee;
+ }
+
+ lookupPeers() {
+ return db.lookup(this.employee, 'peers');
+ }
+
+ lookupMananger() {
+ return db.lookup(this.employee, 'manager');
+ }
+
+ getPeerReviews() {
+ let peers = this.lookupPeers();
+ // ...
+ }
+
+ perfReview() {
+ getPeerReviews();
+ getManagerReview();
+ getSelfReview();
+ }
+
+ getManagerReview() {
+ let manager = this.lookupManager();
+ }
+
+ getSelfReview() {
+ // ...
+ }
+}
+
+let review = new PerformanceReview(user);
+review.perfReview();
+```
+
+```javascript
+// good
+class PerformanceReview {
+ constructor(employee) {
+ this.employee = employee;
+ }
+
+ perfReview() {
+ getPeerReviews();
+ getManagerReview();
+ getSelfReview();
+ }
+
+ getPeerReviews() {
+ let peers = this.lookupPeers();
+ // ...
+ }
+
+ lookupPeers() {
+ return db.lookup(this.employee, 'peers');
+ }
+
+ getManagerReview() {
+ let manager = this.lookupManager();
+ }
+
+ lookupMananger() {
+ return db.lookup(this.employee, 'manager');
+ }
+
+ getSelfReview() {
+ // ...
+ }
+}
+
+let review = new PerformanceReview(employee);
+review.perfReview();
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## [](#comments)**Comments**
+
+
+### [](#only-comment-things-that-have-business-logic-complexity)只注释业务逻辑复杂的内容
+
+注释是用来解释代码的,而不是必须的。好的代码应该 _自注释_。
+
+```javascript
+// bad
+function hashIt(data) {
+ // Hash 码
+ var hash = 0;
+
+ // 字符串长度
+ var length = data.length;
+
+ // 遍历数据中所有字符
+ for (var i = 0; i < length; i++) {
+ // 获取字符编码
+ var char = data.charCodeAt(i);
+ // 生成 Hash
+ hash = ((hash << 5) - hash) + char;
+ // 转换为32位整数
+ hash = hash & hash;
+ }
+}
+```
+
+```javascript
+// good
+function hashIt(data) {
+ var hash = 0;
+ var length = data.length;
+
+ for (var i = 0; i < length; i++) {
+ var char = data.charCodeAt(i);
+ hash = ((hash << 5) - hash) + char;
+
+ // 转换为32位整数
+ hash = hash & hash;
+ }
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#dont-leave-commented-out-code-in-your-codebase)不要把注释掉的代码留在代码库中
+
+版本控制存在的原因就是保存你的历史代码。
+
+```javascript
+// bad
+doStuff();
+// doOtherStuff();
+// doSomeMoreStuff();
+// doSoMuchStuff();
+```
+
+```javascript
+// good
+doStuff();
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#dont-have-journal-comments)不需要日志式的注释
+
+记住,使用版本控制!没用的代码、注释掉的代码,尤其是日志式的注释。用 `git log` 来获取历史信息!
+
+```javascript
+// bad
+/**
+ * 2016-12-20: Removed monads, didn't understand them (RM)
+ * 2016-10-01: Improved using special monads (JP)
+ * 2016-02-03: Removed type-checking (LI)
+ * 2015-03-14: Added combine with type-checking (JR)
+ */
+function combine(a, b) {
+ return a + b;
+}
+```
+
+```javascript
+// good
+function combine(a, b) {
+ return a + b;
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#avoid-positional-markers)避免位置标记
+
+位置标记通常只会添加垃圾信息。通过对函数或变量名以及适当的缩进就能为代码带来良好的可视化结构。
+
+```javascript
+// bad
+////////////////////////////////////////////////////////////////////////////////
+// Scope Model Instantiation
+////////////////////////////////////////////////////////////////////////////////
+let $scope.model = {
+ menu: 'foo',
+ nav: 'bar'
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Action setup
+////////////////////////////////////////////////////////////////////////////////
+let actions = function() {
+ // ...
+}
+```
+
+```javascript
+// good
+let $scope.model = {
+ menu: 'foo',
+ nav: 'bar'
+};
+
+let actions = function() {
+ // ...
+}
+```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+### [](#avoid-legal-comments-in-source-files)避免在源文件中添加版权注释
+
+这是代码文件树顶层的 `LICENSE` 文件应该干的事情。
+
+```javascript
+// bad
+/*
+The MIT License (MIT)
+
+Copyright (c) 2016 Ryan McDermott
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE
+*/
+
+function calculateBill() {
+ // ...
+}
+```
+
+```javascript
+// good
+function calculateBill() {
+ // ...
+}
+```
diff --git a/docs/config-eslint.md b/docs/config-eslint.md
new file mode 100644
index 0000000000..cb828bc5d5
--- /dev/null
+++ b/docs/config-eslint.md
@@ -0,0 +1,170 @@
+
+# ESLint 配置使用
+
+下载 [.eslintrc.js](../.eslintrc.js) 到项目根目录,默认情况下值检测 .js 后缀文件,可以参看扩展组件获得其他需求的支持。
+
+> 为什么选用 `.eslintrc.js` 后缀名?因为 `.json` 没法加注释,格式要求比较严格,而 `.eslintrc` 格式在 vscode 中默认做 json 处理了,其中的注释 # 就显示为了异常,所以统一使用 js 格式,通用了
+
+采用标准:
+
+主要有三种标准:Airbnb,Google 以及 Standard,目前来看,公认的最好的标准是Airbnb标准(互联网发展日新月异,永远是年轻人颠覆老年人,连Google都老了)。它对于ES6要求最严格,比如禁止使用var定义变量,必须使用let或者const等等。既然采用最新标准,当然就让你的代码一次性向最高标准看齐,省得以后麻烦。
+
+NOTE: 可选择扩展组件
+
+- eslint-plugin-html 检测 html 内 js
+- eslint-plugin-react react 规范
+- eslint-plugin-jsx-a11y JSX 代码段内应用 AST 检查器
+- eslint-plugin-promise 回调函数使用最佳实践
+- eslint-plugin-vue 支持 vue 文件
+
+a11y是accessibility(无障碍环境)的缩写,从第一个字母a到最后一个字母y,中间一共是11个字母,所以就叫a11y了,类似于i18n表示internationalization(国际化)一样。
+
+## 项目配置,安装 ESLint 依赖
+
+可以安装到全局,就不必每个项目单独安装了,全部共用
+
+```
+// ES6 推荐使用 airbnb
+npm install -g babel-eslint
+npm install -g eslint eslint-plugin-import eslint-plugin-react eslint-plugin-jsx-a11y eslint-plugin-airbnb
+
+// 之后设置
+extend: 'airbnb',
+```
+
+```
+// ES5 推荐使用 airbnb/es5()
+npm install -g eslint eslint-config-webcoding
+
+// 之后设置
+extend: 'webcoding/configurations/airbnb/es5',
+```
+
+**扩展组件配置**
+
+```
+// 示例:扩展 eslint-plugin-html
+plugins: [
+ // 处理 html 文件内 js 代码规范等
+ 'html',
+],
+// html默认已经包含后缀 .erb, .handlebars, .hbs, .htm, .html, .mustache, .nunjucks, .php, .tag, .twig, .vue, .we,否则要如下设置
+"settings": {
+ // 自定义设置如下
+ // "html/html-extensions": [".html", ".custom"],
+},
+
+// NOTE: 以上配置 ATOM 中可以直接起效,VSCode 中还要增加配置
+"eslint.validate": [
+ "javascript",
+ "javascriptreact",
+ // vscode 要支持 eslint-plugin-html 需要配置这个
+ "html"
+],
+```
+
+
+## 编辑器配置
+
+建议使用 Atom 或 VSCode 编辑器
+
+### Atom
+
+```
+编辑器要安装 linter-eslint 插件
+配置 .eslintrc filePath 为 .eslintrc.js
+勾选 Lint HTML Files (配合 eslint-plugin-html 以支持检测 html 格式文件等)
+勾选选项 Show Rule ID in Messages (错误提示中会显示官网 rules 链接)
+勾选选项 Use global ESLint installation(使用全局组件 eslint)
+```
+
+**小提示:** Atom 编辑器的 eslint 提示,有链接规则直接可打开 ESLint 官网,通过修改配置,可调整为打开对应的中文网站。
+
+```
+Preferences => Open Config Folder => 找到组件 packages/linter-eslint
+ => 找到 node_modules/eslint-rule-documentation/index.js
+ => 将 getRuleURI 函数中 eslint.org/ 修改为 eslint.cn/
+ => 重启见效
+
+参看插件源码: https://github.com/AtomLinter/linter-eslint
+```
+
+### VSCode
+
+```
+编辑器要安装 eslint 插件
+编辑器增加全局配置
+"eslint.options": {
+ "configFile": "./.eslintrc.js"
+},
+
+参看插件源码: https://github.com/Microsoft/vscode-eslint
+```
+
+NOTE:不要修改配置 `"eslint.autoFixOnSave": false,`,如果开启此修复功能,可能会导致意料外的修复发生(自动修复会修复整个文件,低级问题自动修复没问题,但我目前不太相信高级的修复,它能处理好),所以建议手动处理,而针对简单文件,可以绑定快捷键调用此功能。
+
+绑定快捷键到 `eslint.executeAutofix` 可以调用自动修复(Fix all auto-fixable problems),示例如下:
+
+```
+// 绑定为不常用的快捷键,避免误修复,同时可以单手操作的快捷键
+// eslint 发布内容tab 有个命令列表,快捷键就可以绑定到对应的命令上
+{
+ "key": "ctrl+alt+cmd+space",
+ "command": "eslint.executeAutofix",
+ "when": "editorTextFocus"
+}
+
+NOTE: 目前(20170216) VSCode 的提示不允许外链,所以 eslint 插件的提示,也无法做到[提示链接指向官方文档](https://github.com/Microsoft/vscode/issues/11847)
+```
+
+### 其他配置及使用
+
+**编辑器快捷加载项目**
+
+推荐使用 [zsh](http://ohmyz.sh/),配合插件[z](https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/z)实现跟踪/跳转你最常用的目录,配置 plugins=(z)即可。
+
+如此,想要打开一个项目 protest,直接如下即可
+
+```
+# z protest
+//使用 Atom 打开此项目
+# atom .
+//使用 VSCode 打开此项目
+# code .
+```
+
+**同步配置**
+
+推荐安装 Settings Sync 插件,同步自己的配置到云端。
+
+**Code Runner**
+
+使用 Code Runner 插件,支持右键运行代码(使用 node),由于有些新的语法,即使最新版的 node 也不支持,需要借助 babel-cli 以及如下插件来实现。
+
+babel-cli 工具自带一个 babel-node 命令,提供一个支持ES6的REPL环境。它支持Node的REPL环境的所有功能,而且可以直接运行ES6代码。而配合 babel-preset-stage-0 则可以直接支持 ES2017
+
+Code Runner 配置如下:
+
+```
+"code-runner.executorMap": {
+ "javascript": "babel-node --presets stage-0"
+}
+
+NOTE: babel-preset-stage-0 必须要安装到项目目录才可以被引用,安装全局是不行的。
+```
+
+其他插件参考:
+
+```
+# ES2015转码规则
+$ npm install --save-dev babel-preset-es2015
+
+# react转码规则
+$ npm install --save-dev babel-preset-react
+
+# ES7不同阶段语法提案的转码规则(共有4个阶段),选装一个
+$ npm install --save-dev babel-preset-stage-0
+$ npm install --save-dev babel-preset-stage-1
+$ npm install --save-dev babel-preset-stage-2
+$ npm install --save-dev babel-preset-stage-3
+```
diff --git a/docs/es5.eslintrc.js b/docs/es5.eslintrc.js
new file mode 100644
index 0000000000..26697eaebf
--- /dev/null
+++ b/docs/es5.eslintrc.js
@@ -0,0 +1,45 @@
+
+// JS 书写规范
+// http://eslint.org
+// http://standardjs.com/rules.html
+// 具体规范参见文档[javascript-style-guide](https://github.com/webcoding/javascript-style-guide/blob/master/docs)
+
+// 配置参看 [config-eslint.md](https://github.com/webcoding/javascript-style-guide/blob/master/docs/config-eslint.md)
+
+// NOTE: 兼容性设定,放置在项目根目录,同时支持 ES5、ES6 便于切换
+
+module.exports = {
+ root: true,
+ parser: 'babel-eslint',
+ installedESLint: true,
+ parserOptions: {
+ // ecmaVersion: 6,
+ sourceType: 'module',
+ },
+ globals: {
+ Vue: false,
+ },
+
+ plugins: [
+ // 处理 html 文件内 js 代码规范等
+ 'html',
+ ],
+ // extends: 'standard',
+ // ES5 推荐规范
+ extends: 'webcoding/configurations/airbnb/es5',
+ // ES6 推荐规范
+ // extends: 'airbnb',
+ // extends: 'webcoding/configurations/airbnb/es6',
+
+ // add your custom rules here
+ rules: {
+ // 行尾分号,默认配置always,要求在行末加上分号,standard 配置强制不带
+ semi: ['error', 'never'],
+ // 多行模式必须带逗号,单行模式不能带逗号
+ 'comma-dangle': ['error', 'always-multiline'],
+ // 'max-len': ['error', 120],
+ // 禁止使用 console debugger
+ // 'no-console': 1,
+ // 'no-debugger': 1,
+ },
+}
diff --git a/docs/es5.test.js b/docs/es5.test.js
new file mode 100644
index 0000000000..9a342551dd
--- /dev/null
+++ b/docs/es5.test.js
@@ -0,0 +1,93 @@
+
+// ES6 代码规范练习场
+
+// 为便于测试,关闭部分规则检测
+/* eslint no-unused-vars: 0 */
+
+// [类型](#types)
+// 使用 let const 替代 var
+var type11 = 123
+var type2 = 'hello'
+
+const type3 = 123
+let type4 = 123
+// type4 = 456
+const type5 = 'hello'
+
+const type121 = [1, 2]
+const type122 = type121
+type122[0] = 9
+
+console.log(type122[0], type122[0])
+
+
+// [引用](#references)
+
+
+// [对象](#objects)
+
+
+// [数组](#arrays)
+
+
+// [解构](#destructuring)
+
+
+// [字符串](#strings)
+
+
+// [函数](#functions)
+
+
+// [箭头函数](#arrow-functions)
+
+
+// [类 & 构造函数](#classes--constructors)
+
+
+// [模块](#modules)
+
+
+// [Iterators and Generators](#iterators-and-generators)
+
+
+// [属性](#properties)
+
+
+// [变量](#variables)
+
+
+// [提升](#hoisting)
+
+
+// [比较运算符 & 等号](#comparison-operators--equality)
+
+
+// [代码块](#blocks)
+
+
+// [注释](#comments)
+
+
+// [空白](#whitespace)
+
+
+// [逗号](#commas)
+
+
+// [分号](#semicolons)
+
+
+// [类型转换](#type-casting--coercion)
+
+
+// [命名规则](#naming-conventions)
+
+
+// [存取器](#accessors)
+
+
+// [事件](#events)
+
+
+// [jQuery](#jquery)
diff --git a/docs/es5_zh-cn_v1.md b/docs/es5_zh-cn_v1.md
new file mode 100644
index 0000000000..30c5668807
--- /dev/null
+++ b/docs/es5_zh-cn_v1.md
@@ -0,0 +1,1743 @@
+
+source: https://github.com/sivan/javascript-style-guide/blob/master/es5/README.md
+
+# Airbnb JavaScript Style Guide() {
+
+*用更合理的方式写 JavaScript*
+
+## 目录
+
+ 1. [类型](#types)
+ 1. [对象](#objects)
+ 1. [数组](#arrays)
+ 1. [字符串](#strings)
+ 1. [函数](#functions)
+ 1. [属性](#properties)
+ 1. [变量](#variables)
+ 1. [提升](#hoisting)
+ 1. [比较运算符 & 等号](#comparison-operators--equality)
+ 1. [块](#blocks)
+ 1. [注释](#comments)
+ 1. [空白](#whitespace)
+ 1. [逗号](#commas)
+ 1. [分号](#semicolons)
+ 1. [类型转化](#type-casting--coercion)
+ 1. [命名规则](#naming-conventions)
+ 1. [存取器](#accessors)
+ 1. [构造函数](#constructors)
+ 1. [事件](#events)
+ 1. [模块](#modules)
+ 1. [jQuery](#jquery)
+ 1. [ECMAScript 5 兼容性](#ecmascript-5-compatibility)
+ 1. [测试](#testing)
+ 1. [性能](#performance)
+ 1. [资源](#resources)
+ 1. [谁在使用](#in-the-wild)
+ 1. [翻译](#translation)
+ 1. [JavaScript 风格指南说明](#the-javascript-style-guide-guide)
+ 1. [与我们讨论 JavaScript](#chat-with-us-about-javascript)
+ 1. [贡献者](#contributors)
+ 1. [许可](#license)
+
+## 类型
+
+ - **原始值**: 存取直接作用于它自身。
+
+ + `string`
+ + `number`
+ + `boolean`
+ + `null`
+ + `undefined`
+
+ ```javascript
+ var foo = 1;
+ var bar = foo;
+
+ bar = 9;
+
+ console.log(foo, bar); // => 1, 9
+ ```
+ - **复杂类型**: 存取时作用于它自身值的引用。
+
+ + `object`
+ + `array`
+ + `function`
+
+ ```javascript
+ var foo = [1, 2];
+ var bar = foo;
+
+ bar[0] = 9;
+
+ console.log(foo[0], bar[0]); // => 9, 9
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## 对象
+
+ - 使用直接量创建对象。
+
+ ```javascript
+ // bad
+ var item = new Object();
+
+ // good
+ var item = {};
+ ```
+
+ - 不要使用[保留字](http://es5.github.io/#x7.6.1)作为键名,它们在 IE8 下不工作。[更多信息](https://github.com/airbnb/javascript/issues/61)。
+
+ ```javascript
+ // bad
+ var superman = {
+ default: { clark: 'kent' },
+ private: true
+ };
+
+ // good
+ var superman = {
+ defaults: { clark: 'kent' },
+ hidden: true
+ };
+ ```
+
+ - 使用同义词替换需要使用的保留字。
+
+ ```javascript
+ // bad
+ var superman = {
+ class: 'alien'
+ };
+
+ // bad
+ var superman = {
+ klass: 'alien'
+ };
+
+ // good
+ var superman = {
+ type: 'alien'
+ };
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## 数组
+
+ - 使用直接量创建数组。
+
+ ```javascript
+ // bad
+ var items = new Array();
+
+ // good
+ var items = [];
+ ```
+
+ - 向数组增加元素时使用 Array#push 来替代直接赋值。
+
+ ```javascript
+ var someStack = [];
+
+
+ // bad
+ someStack[someStack.length] = 'abracadabra';
+
+ // good
+ someStack.push('abracadabra');
+ ```
+
+ - 当你需要拷贝数组时,使用 Array#slice。[jsPerf](http://jsperf.com/converting-arguments-to-an-array/7)
+
+ ```javascript
+ var len = items.length;
+ var itemsCopy = [];
+ var i;
+
+ // bad
+ for (i = 0; i < len; i++) {
+ itemsCopy[i] = items[i];
+ }
+
+ // good
+ itemsCopy = items.slice();
+ ```
+
+ - 使用 Array#slice 将类数组对象转换成数组。
+
+ ```javascript
+ function trigger() {
+ var args = Array.prototype.slice.call(arguments);
+ ...
+ }
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 字符串
+
+ - 使用单引号 `''` 包裹字符串。
+
+ ```javascript
+ // bad
+ var name = "Bob Parr";
+
+ // good
+ var name = 'Bob Parr';
+
+ // bad
+ var fullName = "Bob " + this.lastName;
+
+ // good
+ var fullName = 'Bob ' + this.lastName;
+ ```
+
+ - 超过 100 个字符的字符串应该使用连接符写成多行。
+ - 注:若过度使用,通过连接符连接的长字符串可能会影响性能。[jsPerf](http://jsperf.com/ya-string-concat) & [讨论](https://github.com/airbnb/javascript/issues/40).
+
+ ```javascript
+ // bad
+ var 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.';
+
+ // bad
+ var 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.';
+
+ // good
+ var 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.';
+ ```
+
+ - 程序化生成的字符串使用 Array#join 连接而不是使用连接符。尤其是 IE 下:[jsPerf](http://jsperf.com/string-vs-array-concat/2).
+
+ ```javascript
+ var items;
+ var messages;
+ var length;
+ var i;
+
+ messages = [{
+ state: 'success',
+ message: 'This one worked.'
+ }, {
+ state: 'success',
+ message: 'This one worked as well.'
+ }, {
+ state: 'error',
+ message: 'This one did not work.'
+ }];
+
+ length = messages.length;
+
+ // bad
+ function inbox(messages) {
+ items = '
';
+
+ for (i = 0; i < length; i++) {
+ items += '- ' + messages[i].message + '
';
+ }
+
+ return items + '
';
+ }
+
+ // good
+ function inbox(messages) {
+ items = [];
+
+ for (i = 0; i < length; i++) {
+ // use direct assignment in this case because we're micro-optimizing.
+ items[i] = '' + messages[i].message + '';
+ }
+
+ return '';
+ }
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 函数
+
+ - 函数表达式:
+
+ ```javascript
+ // 匿名函数表达式
+ var anonymous = function() {
+ return true;
+ };
+
+ // 命名函数表达式
+ var named = function named() {
+ return true;
+ };
+
+ // 立即调用的函数表达式(IIFE)
+ (function () {
+ console.log('Welcome to the Internet. Please follow me.');
+ }());
+ ```
+
+ - 永远不要在一个非函数代码块(if、while 等)中声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但它们的解析表现不一致。
+ - **注:** ECMA-262 把 `块` 定义为一组语句。函数声明不是语句。[阅读对 ECMA-262 这个问题的说明](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97)。
+
+ ```javascript
+ // bad
+ if (currentUser) {
+ function test() {
+ console.log('Nope.');
+ }
+ }
+
+ // good
+ var test;
+ if (currentUser) {
+ test = function test() {
+ console.log('Yup.');
+ };
+ }
+ ```
+
+ - 永远不要把参数命名为 `arguments`。这将取代函数作用域内的 `arguments` 对象。
+
+ ```javascript
+ // bad
+ function nope(name, options, arguments) {
+ // ...stuff...
+ }
+
+ // good
+ function yup(name, options, args) {
+ // ...stuff...
+ }
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+
+## 属性
+
+ - 使用 `.` 来访问对象的属性。
+
+ ```javascript
+ var luke = {
+ jedi: true,
+ age: 28
+ };
+
+ // bad
+ var isJedi = luke['jedi'];
+
+ // good
+ var isJedi = luke.jedi;
+ ```
+
+ - 当通过变量访问属性时使用中括号 `[]`。
+
+ ```javascript
+ var luke = {
+ jedi: true,
+ age: 28
+ };
+
+ function getProp(prop) {
+ return luke[prop];
+ }
+
+ var isJedi = getProp('jedi');
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 变量
+
+ - 总是使用 `var` 来声明变量。不这么做将导致产生全局变量。我们要避免污染全局命名空间。
+
+ ```javascript
+ // bad
+ superPower = new SuperPower();
+
+ // good
+ var superPower = new SuperPower();
+ ```
+
+ - 使用 `var` 声明每一个变量。
+ 这样做的好处是增加新变量将变的更加容易,而且你永远不用再担心调换错 `;` 跟 `,`。
+
+ ```javascript
+ // bad
+ var items = getItems(),
+ goSportsTeam = true,
+ dragonball = 'z';
+
+ // bad
+ // (跟上面的代码比较一下,看看哪里错了)
+ var items = getItems(),
+ goSportsTeam = true;
+ dragonball = 'z';
+
+ // good
+ var items = getItems();
+ var goSportsTeam = true;
+ var dragonball = 'z';
+ ```
+
+ - 最后再声明未赋值的变量。当你需要引用前面的变量赋值时这将变的很有用。
+
+ ```javascript
+ // bad
+ var i, len, dragonball,
+ items = getItems(),
+ goSportsTeam = true;
+
+ // bad
+ var i;
+ var items = getItems();
+ var dragonball;
+ var goSportsTeam = true;
+ var len;
+
+ // good
+ var items = getItems();
+ var goSportsTeam = true;
+ var dragonball;
+ var length;
+ var i;
+ ```
+
+ - 在作用域顶部声明变量。这将帮你避免变量声明提升相关的问题。
+
+ ```javascript
+ // bad
+ function () {
+ test();
+ console.log('doing stuff..');
+
+ //..other stuff..
+
+ var name = getName();
+
+ if (name === 'test') {
+ return false;
+ }
+
+ return name;
+ }
+
+ // good
+ function () {
+ var name = getName();
+
+ test();
+ console.log('doing stuff..');
+
+ //..other stuff..
+
+ if (name === 'test') {
+ return false;
+ }
+
+ return name;
+ }
+
+ // bad - 不必要的函数调用
+ function () {
+ var name = getName();
+
+ if (!arguments.length) {
+ return false;
+ }
+
+ this.setFirstName(name);
+
+ return true;
+ }
+
+ // good
+ function () {
+ var name;
+
+ if (!arguments.length) {
+ return false;
+ }
+
+ name = getName();
+ this.setFirstName(name);
+
+ return true;
+ }
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 提升
+
+ - 变量声明会提升至作用域顶部,但赋值不会。
+
+ ```javascript
+ // 我们知道这样不能正常工作(假设这里没有名为 notDefined 的全局变量)
+ function example() {
+ console.log(notDefined); // => throws a ReferenceError
+ }
+
+ // 但由于变量声明提升的原因,在一个变量引用后再创建它的变量声明将可以正常工作。
+ // 注:变量赋值为 `true` 不会提升。
+ function example() {
+ console.log(declaredButNotAssigned); // => undefined
+ var declaredButNotAssigned = true;
+ }
+
+ // 解释器会把变量声明提升到作用域顶部,意味着我们的例子将被重写成:
+ function example() {
+ var declaredButNotAssigned;
+ console.log(declaredButNotAssigned); // => undefined
+ declaredButNotAssigned = true;
+ }
+ ```
+
+ - 匿名函数表达式会提升它们的变量名,但不会提升函数的赋值。
+
+ ```javascript
+ function example() {
+ console.log(anonymous); // => undefined
+
+ anonymous(); // => TypeError anonymous is not a function
+
+ var anonymous = function () {
+ console.log('anonymous function expression');
+ };
+ }
+ ```
+
+ - 命名函数表达式会提升变量名,但不会提升函数名或函数体。
+
+ ```javascript
+ function example() {
+ console.log(named); // => undefined
+
+ named(); // => TypeError named is not a function
+
+ superPower(); // => ReferenceError superPower is not defined
+
+ var named = function superPower() {
+ console.log('Flying');
+ };
+ }
+
+ // 当函数名跟变量名一样时,表现也是如此。
+ function example() {
+ console.log(named); // => undefined
+
+ named(); // => TypeError named is not a function
+
+ var named = function named() {
+ console.log('named');
+ }
+ }
+ ```
+
+ - 函数声明提升它们的名字和函数体。
+
+ ```javascript
+ function example() {
+ superPower(); // => Flying
+
+ function superPower() {
+ console.log('Flying');
+ }
+ }
+ ```
+
+ - 了解更多信息在 [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) by [Ben Cherry](http://www.adequatelygood.com/).
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+
+## 比较运算符 & 等号
+
+ - 优先使用 `===` 和 `!==` 而不是 `==` 和 `!=`.
+ - 条件表达式例如 `if` 语句通过抽象方法 `ToBoolean` 强制计算它们的表达式并且总是遵守下面的规则:
+
+ + **对象** 被计算为 **true**
+ + **Undefined** 被计算为 **false**
+ + **Null** 被计算为 **false**
+ + **布尔值** 被计算为 **布尔的值**
+ + **数字** 如果是 **+0、-0 或 NaN** 被计算为 **false**,否则为 **true**
+ + **字符串** 如果是空字符串 `''` 被计算为 **false**,否则为 **true**
+
+ ```javascript
+ if ([0]) {
+ // true
+ // 一个数组就是一个对象,对象被计算为 true
+ }
+ ```
+
+ - 使用快捷方式。
+
+ ```javascript
+ // bad
+ if (name !== '') {
+ // ...stuff...
+ }
+
+ // good
+ if (name) {
+ // ...stuff...
+ }
+
+ // bad
+ if (collection.length > 0) {
+ // ...stuff...
+ }
+
+ // good
+ if (collection.length) {
+ // ...stuff...
+ }
+ ```
+
+ - 了解更多信息在 [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll.
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 块
+
+ - 使用大括号包裹所有的多行代码块。
+
+ ```javascript
+ // bad
+ if (test)
+ return false;
+
+ // good
+ if (test) return false;
+
+ // good
+ if (test) {
+ return false;
+ }
+
+ // bad
+ function () { return false; }
+
+ // good
+ function () {
+ return false;
+ }
+ ```
+
+ - 如果通过 `if` 和 `else` 使用多行代码块,把 `else` 放在 `if` 代码块关闭括号的同一行。
+
+ ```javascript
+ // bad
+ if (test) {
+ thing1();
+ thing2();
+ }
+ else {
+ thing3();
+ }
+
+ // good
+ if (test) {
+ thing1();
+ thing2();
+ } else {
+ thing3();
+ }
+ ```
+
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 注释
+
+ - 使用 `/** ... */` 作为多行注释。包含描述、指定所有参数和返回值的类型和值。
+
+ ```javascript
+ // bad
+ // make() returns a new element
+ // based on the passed in tag name
+ //
+ // @param {String} tag
+ // @return {Element} element
+ function make(tag) {
+
+ // ...stuff...
+
+ return element;
+ }
+
+ // good
+ /**
+ * make() returns a new element
+ * based on the passed in tag name
+ *
+ * @param {String} tag
+ * @return {Element} element
+ */
+ function make(tag) {
+
+ // ...stuff...
+
+ return element;
+ }
+ ```
+
+ - 使用 `//` 作为单行注释。在评论对象上面另起一行使用单行注释。在注释前插入空行。
+
+ ```javascript
+ // bad
+ var active = true; // is current tab
+
+ // good
+ // is current tab
+ var active = true;
+
+ // bad
+ function getType() {
+ console.log('fetching type...');
+ // set the default type to 'no type'
+ var type = this.type || 'no type';
+
+ return type;
+ }
+
+ // good
+ function getType() {
+ console.log('fetching type...');
+
+ // set the default type to 'no type'
+ var type = this.type || 'no type';
+
+ return type;
+ }
+ ```
+
+ - 给注释增加 `FIXME` 或 `TODO` 的前缀可以帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。这将有别于常见的注释,因为它们是可操作的。使用 `FIXME -- need to figure this out` 或者 `TODO -- need to implement`。
+
+ - 使用 `// FIXME:` 标注问题。
+
+ ```javascript
+ function Calculator() {
+
+ // FIXME: shouldn't use a global here
+ total = 0;
+
+ return this;
+ }
+ ```
+
+ - 使用 `// TODO:` 标注问题的解决方式。
+
+ ```javascript
+ function Calculator() {
+
+ // TODO: total should be configurable by an options param
+ this.total = 0;
+
+ return this;
+ }
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 空白
+
+ - 使用 2 个空格作为缩进。
+
+ ```javascript
+ // bad
+ function () {
+ ∙∙∙∙var name;
+ }
+
+ // bad
+ function () {
+ ∙var name;
+ }
+
+ // good
+ function () {
+ ∙∙var name;
+ }
+ ```
+
+ - 在大括号前放一个空格。
+
+ ```javascript
+ // bad
+ function test(){
+ console.log('test');
+ }
+
+ // good
+ function test() {
+ console.log('test');
+ }
+
+ // bad
+ dog.set('attr',{
+ age: '1 year',
+ breed: 'Bernese Mountain Dog'
+ });
+
+ // good
+ dog.set('attr', {
+ age: '1 year',
+ breed: 'Bernese Mountain Dog'
+ });
+ ```
+
+ - 在控制语句(`if`、`while` 等)的小括号前放一个空格。在函数调用及声明中,不在函数的参数列表前加空格。
+
+ ```javascript
+ // bad
+ if(isJedi) {
+ fight ();
+ }
+
+ // good
+ if (isJedi) {
+ fight();
+ }
+
+ // bad
+ function fight () {
+ console.log ('Swooosh!');
+ }
+
+ // good
+ function fight() {
+ console.log('Swooosh!');
+ }
+ ```
+
+ - 使用空格把运算符隔开。
+
+ ```javascript
+ // bad
+ var x=y+5;
+
+ // good
+ var x = y + 5;
+ ```
+
+ - 在文件末尾插入一个空行。
+
+ ```javascript
+ // bad
+ (function (global) {
+ // ...stuff...
+ })(this);
+ ```
+
+ ```javascript
+ // bad
+ (function (global) {
+ // ...stuff...
+ })(this);↵
+ ↵
+ ```
+
+ ```javascript
+ // good
+ (function (global) {
+ // ...stuff...
+ })(this);↵
+ ```
+
+ - 在使用长方法链时进行缩进。使用前面的点 `.` 强调这是方法调用而不是新语句。
+
+ ```javascript
+ // bad
+ $('#items').find('.selected').highlight().end().find('.open').updateCount();
+
+ // bad
+ $('#items').
+ find('.selected').
+ highlight().
+ end().
+ find('.open').
+ updateCount();
+
+ // good
+ $('#items')
+ .find('.selected')
+ .highlight()
+ .end()
+ .find('.open')
+ .updateCount();
+
+ // bad
+ var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
+ .attr('width', (radius + margin) * 2).append('svg:g')
+ .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
+ .call(tron.led);
+
+ // good
+ var leds = stage.selectAll('.led')
+ .data(data)
+ .enter().append('svg:svg')
+ .classed('led', true)
+ .attr('width', (radius + margin) * 2)
+ .append('svg:g')
+ .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
+ .call(tron.led);
+ ```
+
+ - 在块末和新语句前插入空行。
+
+ ```javascript
+ // bad
+ if (foo) {
+ return bar;
+ }
+ return baz;
+
+ // good
+ if (foo) {
+ return bar;
+ }
+
+ return baz;
+
+ // bad
+ var obj = {
+ foo: function () {
+ },
+ bar: function () {
+ }
+ };
+ return obj;
+
+ // good
+ var obj = {
+ foo: function () {
+ },
+
+ bar: function () {
+ }
+ };
+
+ return obj;
+ ```
+
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## 逗号
+
+ - 行首逗号: **不需要**。
+
+ ```javascript
+ // bad
+ var story = [
+ once
+ , upon
+ , aTime
+ ];
+
+ // good
+ var story = [
+ once,
+ upon,
+ aTime
+ ];
+
+ // bad
+ var hero = {
+ firstName: 'Bob'
+ , lastName: 'Parr'
+ , heroName: 'Mr. Incredible'
+ , superPower: 'strength'
+ };
+
+ // good
+ var hero = {
+ firstName: 'Bob',
+ lastName: 'Parr',
+ heroName: 'Mr. Incredible',
+ superPower: 'strength'
+ };
+ ```
+
+ - 额外的行末逗号:**不需要**。这样做会在 IE6/7 和 IE9 怪异模式下引起问题。同样,多余的逗号在某些 ES3 的实现里会增加数组的长度。在 ES5 中已经澄清了 ([source](http://es5.github.io/#D)):
+
+ > Edition 5 clarifies the fact that a trailing comma at the end of an ArrayInitialiser does not add to the length of the array. This is not a semantic change from Edition 3 but some implementations may have previously misinterpreted this.
+
+ ```javascript
+ // bad
+ var hero = {
+ firstName: 'Kevin',
+ lastName: 'Flynn',
+ };
+
+ var heroes = [
+ 'Batman',
+ 'Superman',
+ ];
+
+ // good
+ var hero = {
+ firstName: 'Kevin',
+ lastName: 'Flynn'
+ };
+
+ var heroes = [
+ 'Batman',
+ 'Superman'
+ ];
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 分号
+
+ - **使用分号。**
+
+ ```javascript
+ // bad
+ (function () {
+ var name = 'Skywalker'
+ return name
+ })()
+
+ // good
+ (function () {
+ var name = 'Skywalker';
+ return name;
+ })();
+
+ // good (防止函数在两个 IIFE 合并时被当成一个参数
+ ;(function () {
+ var name = 'Skywalker';
+ return name;
+ })();
+ ```
+
+ [了解更多](http://stackoverflow.com/a/7365214/1712802).
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 类型转换
+
+ - 在语句开始时执行类型转换。
+ - 字符串:
+
+ ```javascript
+ // => this.reviewScore = 9;
+
+ // bad
+ var totalScore = this.reviewScore + '';
+
+ // good
+ var totalScore = '' + this.reviewScore;
+
+ // bad
+ var totalScore = '' + this.reviewScore + ' total score';
+
+ // good
+ var totalScore = this.reviewScore + ' total score';
+ ```
+
+ - 使用 `parseInt` 转换数字时总是带上类型转换的基数。
+
+ ```javascript
+ var inputValue = '4';
+
+ // bad
+ var val = new Number(inputValue);
+
+ // bad
+ var val = +inputValue;
+
+ // bad
+ var val = inputValue >> 0;
+
+ // bad
+ var val = parseInt(inputValue);
+
+ // good
+ var val = Number(inputValue);
+
+ // good
+ var val = parseInt(inputValue, 10);
+ ```
+
+ - 如果因为某些原因 `parseInt` 成为你所做的事的瓶颈而需要使用位操作解决[性能问题](http://jsperf.com/coercion-vs-casting/3)时,留个注释说清楚原因和你的目的。
+
+ ```javascript
+ // good
+ /**
+ * parseInt was the reason my code was slow.
+ * Bitshifting the String to coerce it to a
+ * Number made it a lot faster.
+ */
+ var val = inputValue >> 0;
+ ```
+
+ - **注:** 小心使用位操作运算符。数字会被当成 [64 位值](http://es5.github.io/#x4.3.19),但是位操作运算符总是返回 32 位的整数([source](http://es5.github.io/#x11.7))。位操作处理大于 32 位的整数值时还会导致意料之外的行为。[讨论](https://github.com/airbnb/javascript/issues/109)。最大的 32 位整数是 2,147,483,647:
+
+ ```javascript
+ 2147483647 >> 0 //=> 2147483647
+ 2147483648 >> 0 //=> -2147483648
+ 2147483649 >> 0 //=> -2147483647
+ ```
+
+ - 布尔:
+
+ ```javascript
+ var age = 0;
+
+ // bad
+ var hasAge = new Boolean(age);
+
+ // good
+ var hasAge = Boolean(age);
+
+ // good
+ var hasAge = !!age;
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 命名规则
+
+ - 避免单字母命名。命名应具备描述性。
+
+ ```javascript
+ // bad
+ function q() {
+ // ...stuff...
+ }
+
+ // good
+ function query() {
+ // ..stuff..
+ }
+ ```
+
+ - 使用驼峰式命名对象、函数和实例。
+
+ ```javascript
+ // bad
+ var OBJEcttsssss = {};
+ var this_is_my_object = {};
+ var o = {};
+ function c() {}
+
+ // good
+ var thisIsMyObject = {};
+ function thisIsMyFunction() {}
+ ```
+
+ - 使用帕斯卡式命名构造函数或类。
+
+ ```javascript
+ // bad
+ function user(options) {
+ this.name = options.name;
+ }
+
+ var bad = new user({
+ name: 'nope'
+ });
+
+ // good
+ function User(options) {
+ this.name = options.name;
+ }
+
+ var good = new User({
+ name: 'yup'
+ });
+ ```
+
+ - 不要使用下划线前/后缀。
+
+ > 为什么?JavaScript 并没有私有属性或私有方法的概念。虽然使用下划线是表示「私有」的一种共识,但实际上这些属性是完全公开的,它本身就是你公共接口的一部分。这种习惯或许会导致开发者错误的认为改动它不会造成破坏或者不需要去测试。长话短说:如果你想要某处为「私有」,它必须不能是显式提出的。
+
+ ```javascript
+ // bad
+ this.__firstName__ = 'Panda';
+ this.firstName_ = 'Panda';
+ this._firstName = 'Panda';
+
+ // good
+ this.firstName = 'Panda';
+ ```
+
+ - 不要保存 `this` 的引用。使用 Function#bind。
+
+ ```javascript
+ // bad
+ function () {
+ var self = this;
+ return function () {
+ console.log(self);
+ };
+ }
+
+ // bad
+ function () {
+ var that = this;
+ return function () {
+ console.log(that);
+ };
+ }
+
+ // bad
+ function () {
+ var _this = this;
+ return function () {
+ console.log(_this);
+ };
+ }
+
+ // good
+ function () {
+ return function () {
+ console.log(this);
+ }.bind(this);
+ }
+ ```
+
+ - 给函数命名。这在做堆栈轨迹时很有帮助。
+
+ ```javascript
+ // bad
+ var log = function (msg) {
+ console.log(msg);
+ };
+
+ // good
+ var log = function log(msg) {
+ console.log(msg);
+ };
+ ```
+
+ - **注:** IE8 及以下版本对命名函数表达式的处理有些怪异。了解更多信息到 [http://kangax.github.io/nfe/](http://kangax.github.io/nfe/)。
+
+ - 如果你的文件导出一个类,你的文件名应该与类名完全相同。
+ ```javascript
+ // file contents
+ class CheckBox {
+ // ...
+ }
+ module.exports = CheckBox;
+
+ // in some other file
+ // bad
+ var CheckBox = require('./checkBox');
+
+ // bad
+ var CheckBox = require('./check_box');
+
+ // good
+ var CheckBox = require('./CheckBox');
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 存取器
+
+ - 属性的存取函数不是必须的。
+ - 如果你需要存取函数时使用 `getVal()` 和 `setVal('hello')`。
+
+ ```javascript
+ // bad
+ dragon.age();
+
+ // good
+ dragon.getAge();
+
+ // bad
+ dragon.age(25);
+
+ // good
+ dragon.setAge(25);
+ ```
+
+ - 如果属性是布尔值,使用 `isVal()` 或 `hasVal()`。
+
+ ```javascript
+ // bad
+ if (!dragon.age()) {
+ return false;
+ }
+
+ // good
+ if (!dragon.hasAge()) {
+ return false;
+ }
+ ```
+
+ - 创建 get() 和 set() 函数是可以的,但要保持一致。
+
+ ```javascript
+ function Jedi(options) {
+ options || (options = {});
+ var lightsaber = options.lightsaber || 'blue';
+ this.set('lightsaber', lightsaber);
+ }
+
+ Jedi.prototype.set = function set(key, val) {
+ this[key] = val;
+ };
+
+ Jedi.prototype.get = function get(key) {
+ return this[key];
+ };
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 构造函数
+
+ - 给对象原型分配方法,而不是使用一个新对象覆盖原型。覆盖原型将导致继承出现问题:重设原型将覆盖原有原型!
+
+ ```javascript
+ function Jedi() {
+ console.log('new jedi');
+ }
+
+ // bad
+ Jedi.prototype = {
+ fight: function fight() {
+ console.log('fighting');
+ },
+
+ block: function block() {
+ console.log('blocking');
+ }
+ };
+
+ // good
+ Jedi.prototype.fight = function fight() {
+ console.log('fighting');
+ };
+
+ Jedi.prototype.block = function block() {
+ console.log('blocking');
+ };
+ ```
+
+ - 方法可以返回 `this` 来实现方法链式使用。
+
+ ```javascript
+ // bad
+ Jedi.prototype.jump = function jump() {
+ this.jumping = true;
+ return true;
+ };
+
+ Jedi.prototype.setHeight = function setHeight(height) {
+ this.height = height;
+ };
+
+ var luke = new Jedi();
+ luke.jump(); // => true
+ luke.setHeight(20); // => undefined
+
+ // good
+ Jedi.prototype.jump = function jump() {
+ this.jumping = true;
+ return this;
+ };
+
+ Jedi.prototype.setHeight = function setHeight(height) {
+ this.height = height;
+ return this;
+ };
+
+ var luke = new Jedi();
+
+ luke.jump()
+ .setHeight(20);
+ ```
+
+
+ - 写一个自定义的 `toString()` 方法是可以的,但是确保它可以正常工作且不会产生副作用。
+
+ ```javascript
+ function Jedi(options) {
+ options || (options = {});
+ this.name = options.name || 'no name';
+ }
+
+ Jedi.prototype.getName = function getName() {
+ return this.name;
+ };
+
+ Jedi.prototype.toString = function toString() {
+ return 'Jedi - ' + this.getName();
+ };
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 事件
+
+ - 当给事件附加数据时(无论是 DOM 事件还是私有事件),传入一个哈希而不是原始值。这样可以让后面的贡献者增加更多数据到事件数据而无需找出并更新事件的每一个处理器。例如,不好的写法:
+
+ ```js
+ // bad
+ $(this).trigger('listingUpdated', listing.id);
+
+ ...
+
+ $(this).on('listingUpdated', function (e, listingId) {
+ // do something with listingId
+ });
+ ```
+
+ 更好的写法:
+
+ ```js
+ // good
+ $(this).trigger('listingUpdated', { listingId : listing.id });
+
+ ...
+
+ $(this).on('listingUpdated', function (e, data) {
+ // do something with data.listingId
+ });
+ ```
+
+ **[⬆ 回到顶部](#table-of-contents)**
+
+
+## 模块
+
+ - 模块应该以 `!` 开始。这样确保了当一个不好的模块忘记包含最后的分号时,在合并代码到生产环境后不会产生错误。[详细说明](https://github.com/airbnb/javascript/issues/44#issuecomment-13063933)
+ - 文件应该以驼峰式命名,并放在同名的文件夹里,且与导出的名字一致。
+ - 增加一个名为 `noConflict()` 的方法来设置导出的模块为前一个版本并返回它。
+ - 永远在模块顶部声明 `'use strict';`。
+
+ ```javascript
+ // fancyInput/fancyInput.js
+
+ !function (global) {
+ 'use strict';
+
+ var previousFancyInput = global.FancyInput;
+
+ function FancyInput(options) {
+ this.options = options || {};
+ }
+
+ FancyInput.noConflict = function noConflict() {
+ global.FancyInput = previousFancyInput;
+ return FancyInput;
+ };
+
+ global.FancyInput = FancyInput;
+ }(this);
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## jQuery
+
+ - 使用 `$` 作为存储 jQuery 对象的变量名前缀。
+
+ ```javascript
+ // bad
+ var sidebar = $('.sidebar');
+
+ // good
+ var $sidebar = $('.sidebar');
+ ```
+
+ - 缓存 jQuery 查询。
+
+ ```javascript
+ // bad
+ function setSidebar() {
+ $('.sidebar').hide();
+
+ // ...stuff...
+
+ $('.sidebar').css({
+ 'background-color': 'pink'
+ });
+ }
+
+ // good
+ function setSidebar() {
+ var $sidebar = $('.sidebar');
+ $sidebar.hide();
+
+ // ...stuff...
+
+ $sidebar.css({
+ 'background-color': 'pink'
+ });
+ }
+ ```
+
+ - 对 DOM 查询使用层叠 `$('.sidebar ul')` 或 父元素 > 子元素 `$('.sidebar > ul')`。 [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)
+ - 对有作用域的 jQuery 对象查询使用 `find`。
+
+ ```javascript
+ // bad
+ $('ul', '.sidebar').hide();
+
+ // bad
+ $('.sidebar').find('ul').hide();
+
+ // good
+ $('.sidebar ul').hide();
+
+ // good
+ $('.sidebar > ul').hide();
+
+ // good
+ $sidebar.find('ul').hide();
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## ECMAScript 5 兼容性
+
+ - 参考 [Kangax](https://twitter.com/kangax/) 的 ES5 [兼容表](http://kangax.github.com/es5-compat-table/).
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 测试
+
+ - **Yup.**
+
+ ```javascript
+ function () {
+ return true;
+ }
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 性能
+
+ - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/)
+ - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2)
+ - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost)
+ - [Bang Function](http://jsperf.com/bang-function)
+ - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13)
+ - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text)
+ - [Long String Concatenation](http://jsperf.com/ya-string-concat)
+ - Loading...
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 资源
+
+
+**推荐阅读**
+
+ - [Annotated ECMAScript 5.1](http://es5.github.com/)
+
+**工具**
+
+ - Code Style Linters
+ + [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/.jshintrc)
+ + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json)
+
+**其它风格指南**
+
+ - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml)
+ - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines)
+ - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/)
+ - [JavaScript Standard Style](https://github.com/feross/standard)
+
+**其它风格**
+
+ - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen
+ - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen
+ - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun
+ - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman
+
+**进一步阅读**
+
+ - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll
+ - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer
+ - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz
+ - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban
+ - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock
+
+**书籍**
+
+ - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford
+ - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov
+ - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz
+ - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders
+ - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas
+ - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw
+ - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig
+ - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch
+ - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault
+ - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg
+ - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
+ - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon
+ - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov
+ - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman
+ - [Eloquent JavaScript](http://eloquentjavascript.net) - Marijn Haverbeke
+ - [You Don't Know JS](https://github.com/getify/You-Dont-Know-JS) - Kyle Simpson
+
+**博客**
+
+ - [DailyJS](http://dailyjs.com/)
+ - [JavaScript Weekly](http://javascriptweekly.com/)
+ - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/)
+ - [Bocoup Weblog](http://weblog.bocoup.com/)
+ - [Adequately Good](http://www.adequatelygood.com/)
+ - [NCZOnline](http://www.nczonline.net/)
+ - [Perfection Kills](http://perfectionkills.com/)
+ - [Ben Alman](http://benalman.com/)
+ - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/)
+ - [Dustin Diaz](http://dustindiaz.com/)
+ - [nettuts](http://net.tutsplus.com/?s=javascript)
+
+**播客**
+
+ - [JavaScript Jabber](http://devchat.tv/js-jabber/)
+
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## 谁在使用
+
+ 这是一个使用本风格指南的组织列表。给我们发 pull request 或开一个 issue 让我们将你增加到列表上。
+
+ - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript)
+ - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript)
+ - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript)
+ - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript)
+ - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript)
+ - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript)
+ - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide)
+ - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript)
+ - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript)
+ - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide)
+ - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript)
+ - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide)
+ - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript)
+ - **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript)
+ - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style)
+ - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript)
+ - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript)
+ - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide)
+ - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript)
+ - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions)
+ - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript)
+ - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/javascript)
+ - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript)
+ - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript)
+ - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript)
+ - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript)
+ - **Muber**: [muber/javascript](https://github.com/muber/javascript)
+ - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript)
+ - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript)
+ - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript)
+ - **Nordic Venture Family**: [CodeDistillery/javascript](https://github.com/CodeDistillery/javascript)
+ - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript)
+ - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript)
+ - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide)
+ - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript)
+ - **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide)
+ - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide)
+ - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide)
+ - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript)
+ - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/javascript)
+ - **Super**: [SuperJobs/javascript](https://github.com/SuperJobs/javascript)
+ - **SysGarage**: [sysgarage/javascript-style-guide](https://github.com/sysgarage/javascript-style-guide)
+ - **Target**: [target/javascript](https://github.com/target/javascript)
+ - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript)
+ - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript)
+ - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide)
+ - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript)
+ - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript)
+ - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript)
+
+## 翻译
+
+ 这份风格指南也提供了其它语言的版本:
+
+ -  **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide)
+ -  **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript)
+ -  **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide)
+ -  **Chinese(Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript)
+ -  **Chinese(Simplified)**: [sivan/javascript](https://github.com/sivan/javascript)
+ -  **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide)
+ -  **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide)
+ -  **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide)
+ -  **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide)
+ -  **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide)
+ -  **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript)
+ -  **Russian**: [uprock/javascript](https://github.com/uprock/javascript)
+ -  **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide)
+ -  **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide)
+
+## JavaScript 风格指南说明
+
+ - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide)
+
+## 与我们讨论 JavaScript
+
+ - Find us on [gitter](https://gitter.im/airbnb/javascript).
+
+## 贡献者
+
+ - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors)
+
+
+## 许可
+
+(The MIT License)
+
+Copyright (c) 2014 Airbnb
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+# };
diff --git a/docs/es5_zh-cn_v2.md b/docs/es5_zh-cn_v2.md
new file mode 100644
index 0000000000..3ebaff4d03
--- /dev/null
+++ b/docs/es5_zh-cn_v2.md
@@ -0,0 +1,1331 @@
+
+source: https://github.com/adamlu/javascript-style-guide
+
+[原文: https://github.com/airbnb/javascript](https://github.com/airbnb/javascript)
+
+注:本人根据自己的开发习惯删除和修改了部分规范
+
+# JavaScript规范
+
+## 内容列表
+
+ 1. [类型](#types)
+ 1. [对象](#objects)
+ 1. [数组](#arrays)
+ 1. [字符串](#strings)
+ 1. [函数](#functions)
+ 1. [属性](#properties)
+ 1. [变量](#variables)
+ 1. [条件表达式和等号](#conditionals)
+ 1. [块](#blocks)
+ 1. [注释](#comments)
+ 1. [空白](#whitespace)
+ 1. [逗号](#commas)
+ 1. [分号](#semicolons)
+ 1. [类型转换](#type-coercion)
+ 1. [命名约定](#naming-conventions)
+ 1. [存取器](#accessors)
+ 1. [构造器](#constructors)
+ 1. [事件](#events)
+ 1. [模块](#modules)
+ 1. [jQuery](#jquery)
+ 1. [ES5 兼容性](#es5)
+ 1. [性能](#performance)
+ 1. [资源](#resources)
+ 1. [哪些人在使用](#in-the-wild)
+ 1. [翻译](#translation)
+ 1. [JavaScript风格指南](#guide-guide)
+ 1. [贡献者](#contributors)
+ 1. [许可](#license)
+
+## 类型
+
+ - **原始值**: 相当于传值
+
+ + `string`
+ + `number`
+ + `boolean`
+ + `null`
+ + `undefined`
+
+ ```javascript
+ var foo = 1,
+ bar = foo;
+
+ bar = 9;
+
+ console.log(foo, bar); // => 1, 9
+ ```
+ - **复杂类型**: 相当于传引用
+
+ + `object`
+ + `array`
+ + `function`
+
+ ```javascript
+ var foo = [1, 2],
+ bar = foo;
+
+ bar[0] = 9;
+
+ console.log(foo[0], bar[0]); // => 9, 9
+ ```
+
+ **[[⬆]](#TOC)**
+
+## 对象
+
+ - 使用字面值创建对象
+
+ ```javascript
+ // bad
+ var item = new Object();
+
+ // good
+ var item = {};
+ ```
+
+ - 不要使用保留字 [reserved words](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Reserved_Words) 作为键
+
+ ```javascript
+ // bad
+ var superman = {
+ class: 'superhero',
+ default: { clark: 'kent' },
+ private: true
+ };
+
+ // good
+ var superman = {
+ klass: 'superhero',
+ defaults: { clark: 'kent' },
+ hidden: true
+ };
+ ```
+ **[[⬆]](#TOC)**
+
+## 数组
+
+ - 使用字面值创建数组
+
+ ```javascript
+ // bad
+ var items = new Array();
+
+ // good
+ var items = [];
+ ```
+
+ - 如果你不知道数组的长度,使用push
+
+ ```javascript
+ var someStack = [];
+
+
+ // bad
+ someStack[someStack.length] = 'abracadabra';
+
+ // good
+ someStack.push('abracadabra');
+ ```
+
+ - 当你需要拷贝数组时使用slice. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7)
+
+ ```javascript
+ var len = items.length,
+ itemsCopy = [],
+ i;
+
+ // bad
+ for (i = 0; i < len; i++) {
+ itemsCopy[i] = items[i];
+ }
+
+ // good
+ itemsCopy = items.slice();
+ ```
+
+ - 使用slice将类数组的对象转成数组.
+
+ ```javascript
+ function trigger() {
+ var args = Array.prototype.slice.call(arguments);
+ ...
+ }
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## 字符串
+
+ - 对字符串使用单引号 `''`
+
+ ```javascript
+ // bad
+ var name = "Bob Parr";
+
+ // good
+ var name = 'Bob Parr';
+
+ // bad
+ var fullName = "Bob " + this.lastName;
+
+ // good
+ var fullName = 'Bob ' + this.lastName;
+ ```
+
+ - 超过80个字符的字符串应该使用字符串连接换行
+ - 注: 如果过度使用,长字符串连接可能会对性能有影响. [jsPerf](http://jsperf.com/ya-string-concat) & [Discussion](https://github.com/airbnb/javascript/issues/40)
+
+ ```javascript
+ // bad
+ var 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.';
+
+ // bad
+ var 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.';
+
+
+ // good
+ var 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.';
+ ```
+
+ - 编程时使用join而不是字符串连接来构建字符串,特别是IE: [jsPerf](http://jsperf.com/string-vs-array-concat/2).
+
+ ```javascript
+ var items,
+ messages,
+ length, i;
+
+ messages = [{
+ state: 'success',
+ message: 'This one worked.'
+ },{
+ state: 'success',
+ message: 'This one worked as well.'
+ },{
+ state: 'error',
+ message: 'This one did not work.'
+ }];
+
+ length = messages.length;
+
+ // bad
+ function inbox(messages) {
+ items = '';
+
+ for (i = 0; i < length; i++) {
+ items += '- ' + messages[i].message + '
';
+ }
+
+ return items + '
';
+ }
+
+ // good
+ function inbox(messages) {
+ items = [];
+
+ for (i = 0; i < length; i++) {
+ items[i] = messages[i].message;
+ }
+
+ return '';
+ }
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## 函数
+
+ - 函数表达式:
+
+ ```javascript
+ // 匿名函数表达式
+ var anonymous = function() {
+ return true;
+ };
+
+ // 有名函数表达式
+ var named = function named() {
+ return true;
+ };
+
+ // 立即调用函数表达式
+ (function() {
+ console.log('Welcome to the Internet. Please follow me.');
+ })();
+ ```
+
+ - 绝对不要在一个非函数块里声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但是它们解析不同。
+ - **注:** ECMA-262定义把`块`定义为一组语句,函数声明不是一个语句。[阅读ECMA-262对这个问题的说明](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97).
+
+ ```javascript
+ // bad
+ if (currentUser) {
+ function test() {
+ console.log('Nope.');
+ }
+ }
+
+ // good
+ if (currentUser) {
+ var test = function test() {
+ console.log('Yup.');
+ };
+ }
+ ```
+
+ - 绝对不要把参数命名为 `arguments`, 这将会逾越函数作用域内传过来的 `arguments` 对象.
+
+ ```javascript
+ // bad
+ function nope(name, options, arguments) {
+ // ...stuff...
+ }
+
+ // good
+ function yup(name, options, args) {
+ // ...stuff...
+ }
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## 属性
+
+ - 当使用变量访问属性时使用中括号.
+
+ ```javascript
+ var luke = {
+ jedi: true,
+ age: 28
+ };
+
+ function getProp(prop) {
+ return luke[prop];
+ }
+
+ var isJedi = getProp('jedi');
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## 变量
+
+ - 总是使用 `var` 来声明变量,如果不这么做将导致产生全局变量,我们要避免污染全局命名空间。
+
+ ```javascript
+ // bad
+ superPower = new SuperPower();
+
+ // good
+ var superPower = new SuperPower();
+ ```
+
+ - 使用一个 `var` 以及新行声明多个变量,缩进4个空格。
+
+ ```javascript
+ // bad
+ var items = getItems();
+ var goSportsTeam = true;
+ var dragonball = 'z';
+
+ // good
+ var items = getItems(),
+ goSportsTeam = true,
+ dragonball = 'z';
+ ```
+
+ - 最后再声明未赋值的变量,当你想引用之前已赋值变量的时候很有用。
+
+ ```javascript
+ // bad
+ var i, len, dragonball,
+ items = getItems(),
+ goSportsTeam = true;
+
+ // bad
+ var i, items = getItems(),
+ dragonball,
+ goSportsTeam = true,
+ len;
+
+ // good
+ var items = getItems(),
+ goSportsTeam = true,
+ dragonball,
+ length,
+ i;
+ ```
+
+ - 在作用域顶部声明变量,避免变量声明和赋值引起的相关问题。
+
+ ```javascript
+ // bad
+ function() {
+ test();
+ console.log('doing stuff..');
+
+ //..other stuff..
+
+ var name = getName();
+
+ if (name === 'test') {
+ return false;
+ }
+
+ return name;
+ }
+
+ // good
+ function() {
+ var name = getName();
+
+ test();
+ console.log('doing stuff..');
+
+ //..other stuff..
+
+ if (name === 'test') {
+ return false;
+ }
+
+ return name;
+ }
+
+ // bad
+ function() {
+ var name = getName();
+
+ if (!arguments.length) {
+ return false;
+ }
+
+ return true;
+ }
+
+ // good
+ function() {
+ if (!arguments.length) {
+ return false;
+ }
+
+ var name = getName();
+
+ return true;
+ }
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## 条件表达式和等号
+
+ - 适当使用 `===` 和 `!==` 以及 `==` 和 `!=`.
+ - 条件表达式的强制类型转换遵循以下规则:
+
+ + **对象** 被计算为 **true**
+ + **Undefined** 被计算为 **false**
+ + **Null** 被计算为 **false**
+ + **布尔值** 被计算为 **布尔的值**
+ + **数字** 如果是 **+0, -0, or NaN** 被计算为 **false** , 否则为 **true**
+ + **字符串** 如果是空字符串 `''` 则被计算为 **false**, 否则为 **true**
+
+ ```javascript
+ if ([0]) {
+ // true
+ // An array is an object, objects evaluate to true
+ }
+ ```
+
+ - 使用快捷方式.
+
+ ```javascript
+ // bad
+ if (name !== '') {
+ // ...stuff...
+ }
+
+ // good
+ if (name) {
+ // ...stuff...
+ }
+
+ // bad
+ if (collection.length > 0) {
+ // ...stuff...
+ }
+
+ // good
+ if (collection.length) {
+ // ...stuff...
+ }
+ ```
+
+ - 阅读 [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) 了解更多
+
+ **[[⬆]](#TOC)**
+
+
+## 块
+
+ - 给所有多行的块使用大括号
+
+ ```javascript
+ // bad
+ if (test)
+ return false;
+
+ // good
+ if (test) return false;
+
+ // good
+ if (test) {
+ return false;
+ }
+
+ // bad
+ function() { return false; }
+
+ // good
+ function() {
+ return false;
+ }
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## 注释
+
+ - 使用 `/** ... */` 进行多行注释,包括描述,指定类型以及参数值和返回值
+
+ ```javascript
+ // bad
+ // make() returns a new element
+ // based on the passed in tag name
+ //
+ // @param tag
+ // @return element
+ function make(tag) {
+
+ // ...stuff...
+
+ return element;
+ }
+
+ // good
+ /**
+ * make() returns a new element
+ * based on the passed in tag name
+ *
+ * @param tag
+ * @return element
+ */
+ function make(tag) {
+
+ // ...stuff...
+
+ return element;
+ }
+ ```
+
+ - 使用 `//` 进行单行注释,在评论对象的上面进行单行注释,注释前放一个空行.
+
+ ```javascript
+ // bad
+ var active = true; // is current tab
+
+ // good
+ // is current tab
+ var active = true;
+
+ // bad
+ function getType() {
+ console.log('fetching type...');
+ // set the default type to 'no type'
+ var type = this._type || 'no type';
+
+ return type;
+ }
+
+ // good
+ function getType() {
+ console.log('fetching type...');
+
+ // set the default type to 'no type'
+ var type = this._type || 'no type';
+
+ return type;
+ }
+ ```
+
+ - 如果你有一个问题需要重新来看一下或如果你建议一个需要被实现的解决方法的话需要在你的注释前面加上 `FIXME` 或 `TODO` 帮助其他人迅速理解
+
+ ```javascript
+ function Calculator() {
+
+ // FIXME: shouldn't use a global here
+ total = 0;
+
+ return this;
+ }
+ ```
+
+ ```javascript
+ function Calculator() {
+
+ // TODO: total should be configurable by an options param
+ this.total = 0;
+
+ return this;
+ }
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## 空白
+
+ - 将tab设为4个空格
+
+ ```javascript
+ // bad
+ function() {
+ ∙∙var name;
+ }
+
+ // bad
+ function() {
+ ∙var name;
+ }
+
+ // good
+ function() {
+ ∙∙∙∙var name;
+ }
+ ```
+ - 大括号前放一个空格
+
+ ```javascript
+ // bad
+ function test(){
+ console.log('test');
+ }
+
+ // good
+ function test() {
+ console.log('test');
+ }
+
+ // bad
+ dog.set('attr',{
+ age: '1 year',
+ breed: 'Bernese Mountain Dog'
+ });
+
+ // good
+ dog.set('attr', {
+ age: '1 year',
+ breed: 'Bernese Mountain Dog'
+ });
+ ```
+
+ - 在做长方法链时使用缩进.
+
+ ```javascript
+ // bad
+ $('#items').find('.selected').highlight().end().find('.open').updateCount();
+
+ // good
+ $('#items')
+ .find('.selected')
+ .highlight()
+ .end()
+ .find('.open')
+ .updateCount();
+
+ // bad
+ var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
+ .attr('width', (radius + margin) * 2).append('svg:g')
+ .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
+ .call(tron.led);
+
+ // good
+ var leds = stage.selectAll('.led')
+ .data(data)
+ .enter().append('svg:svg')
+ .class('led', true)
+ .attr('width', (radius + margin) * 2)
+ .append('svg:g')
+ .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
+ .call(tron.led);
+ ```
+
+ **[[⬆]](#TOC)**
+
+## 逗号
+
+ - 不要将逗号放前面
+
+ ```javascript
+ // bad
+ var once
+ , upon
+ , aTime;
+
+ // good
+ var once,
+ upon,
+ aTime;
+
+ // bad
+ var hero = {
+ firstName: 'Bob'
+ , lastName: 'Parr'
+ , heroName: 'Mr. Incredible'
+ , superPower: 'strength'
+ };
+
+ // good
+ var hero = {
+ firstName: 'Bob',
+ lastName: 'Parr',
+ heroName: 'Mr. Incredible',
+ superPower: 'strength'
+ };
+ ```
+
+ - 不要加多余的逗号,这可能会在IE下引起错误,同时如果多一个逗号某些ES3的实现会计算多数组的长度。
+
+ ```javascript
+ // bad
+ var hero = {
+ firstName: 'Kevin',
+ lastName: 'Flynn',
+ };
+
+ var heroes = [
+ 'Batman',
+ 'Superman',
+ ];
+
+ // good
+ var hero = {
+ firstName: 'Kevin',
+ lastName: 'Flynn'
+ };
+
+ var heroes = [
+ 'Batman',
+ 'Superman'
+ ];
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## 分号
+
+ - 语句结束一定要加分号
+
+ ```javascript
+ // bad
+ (function() {
+ var name = 'Skywalker'
+ return name
+ })()
+
+ // good
+ (function() {
+ var name = 'Skywalker';
+ return name;
+ })();
+
+ // good
+ ;(function() {
+ var name = 'Skywalker';
+ return name;
+ })();
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## 类型转换
+
+ - 在语句的开始执行类型转换.
+ - 字符串:
+
+ ```javascript
+ // => this.reviewScore = 9;
+
+ // bad
+ var totalScore = this.reviewScore + '';
+
+ // good
+ var totalScore = '' + this.reviewScore;
+
+ // bad
+ var totalScore = '' + this.reviewScore + ' total score';
+
+ // good
+ var totalScore = this.reviewScore + ' total score';
+ ```
+
+ - 对数字使用 `parseInt` 并且总是带上类型转换的基数.
+
+ ```javascript
+ var inputValue = '4';
+
+ // bad
+ var val = new Number(inputValue);
+
+ // bad
+ var val = +inputValue;
+
+ // bad
+ var val = inputValue >> 0;
+
+ // bad
+ var val = parseInt(inputValue);
+
+ // good
+ var val = Number(inputValue);
+
+ // good
+ var val = parseInt(inputValue, 10);
+
+ // good
+ /**
+ * parseInt was the reason my code was slow.
+ * Bitshifting the String to coerce it to a
+ * Number made it a lot faster.
+ */
+ var val = inputValue >> 0;
+ ```
+
+ - 布尔值:
+
+ ```javascript
+ var age = 0;
+
+ // bad
+ var hasAge = new Boolean(age);
+
+ // good
+ var hasAge = Boolean(age);
+
+ // good
+ var hasAge = !!age;
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## 命名约定
+
+ - 避免单个字符名,让你的变量名有描述意义。
+
+ ```javascript
+ // bad
+ function q() {
+ // ...stuff...
+ }
+
+ // good
+ function query() {
+ // ..stuff..
+ }
+ ```
+
+ - 当命名对象、函数和实例时使用驼峰命名规则
+
+ ```javascript
+ // bad
+ var OBJEcttsssss = {};
+ var this_is_my_object = {};
+ var this-is-my-object = {};
+ function c() {};
+ var u = new user({
+ name: 'Bob Parr'
+ });
+
+ // good
+ var thisIsMyObject = {};
+ function thisIsMyFunction() {};
+ var user = new User({
+ name: 'Bob Parr'
+ });
+ ```
+
+ - 当命名构造函数或类时使用驼峰式大写
+
+ ```javascript
+ // bad
+ function user(options) {
+ this.name = options.name;
+ }
+
+ var bad = new user({
+ name: 'nope'
+ });
+
+ // good
+ function User(options) {
+ this.name = options.name;
+ }
+
+ var good = new User({
+ name: 'yup'
+ });
+ ```
+
+ - 命名私有属性时前面加个下划线 `_`
+
+ ```javascript
+ // bad
+ this.__firstName__ = 'Panda';
+ this.firstName_ = 'Panda';
+
+ // good
+ this._firstName = 'Panda';
+ ```
+
+ - 当保存对 `this` 的引用时使用 `_this`.
+
+ ```javascript
+ // bad
+ function() {
+ var self = this;
+ return function() {
+ console.log(self);
+ };
+ }
+
+ // bad
+ function() {
+ var that = this;
+ return function() {
+ console.log(that);
+ };
+ }
+
+ // good
+ function() {
+ var _this = this;
+ return function() {
+ console.log(_this);
+ };
+ }
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## 存取器
+
+ - 属性的存取器函数不是必需的
+ - 如果你确实有存取器函数的话使用getVal() 和 setVal('hello')
+
+ ```javascript
+ // bad
+ dragon.age();
+
+ // good
+ dragon.getAge();
+
+ // bad
+ dragon.age(25);
+
+ // good
+ dragon.setAge(25);
+ ```
+
+ - 如果属性是布尔值,使用isVal() 或 hasVal()
+
+ ```javascript
+ // bad
+ if (!dragon.age()) {
+ return false;
+ }
+
+ // good
+ if (!dragon.hasAge()) {
+ return false;
+ }
+ ```
+
+ - 可以创建get()和set()函数,但是要保持一致
+
+ ```javascript
+ function Jedi(options) {
+ options || (options = {});
+ var lightsaber = options.lightsaber || 'blue';
+ this.set('lightsaber', lightsaber);
+ }
+
+ Jedi.prototype.set = function(key, val) {
+ this[key] = val;
+ };
+
+ Jedi.prototype.get = function(key) {
+ return this[key];
+ };
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## 构造器
+
+ - 给对象原型分配方法,而不是用一个新的对象覆盖原型,覆盖原型会使继承出现问题。
+
+ ```javascript
+ function Jedi() {
+ console.log('new jedi');
+ }
+
+ // bad
+ Jedi.prototype = {
+ fight: function fight() {
+ console.log('fighting');
+ },
+
+ block: function block() {
+ console.log('blocking');
+ }
+ };
+
+ // good
+ Jedi.prototype.fight = function fight() {
+ console.log('fighting');
+ };
+
+ Jedi.prototype.block = function block() {
+ console.log('blocking');
+ };
+ ```
+
+ - 方法可以返回 `this` 帮助方法可链。
+
+ ```javascript
+ // bad
+ Jedi.prototype.jump = function() {
+ this.jumping = true;
+ return true;
+ };
+
+ Jedi.prototype.setHeight = function(height) {
+ this.height = height;
+ };
+
+ var luke = new Jedi();
+ luke.jump(); // => true
+ luke.setHeight(20) // => undefined
+
+ // good
+ Jedi.prototype.jump = function() {
+ this.jumping = true;
+ return this;
+ };
+
+ Jedi.prototype.setHeight = function(height) {
+ this.height = height;
+ return this;
+ };
+
+ var luke = new Jedi();
+
+ luke.jump()
+ .setHeight(20);
+ ```
+
+
+ - 可以写一个自定义的toString()方法,但是确保它工作正常并且不会有副作用。
+
+ ```javascript
+ function Jedi(options) {
+ options || (options = {});
+ this.name = options.name || 'no name';
+ }
+
+ Jedi.prototype.getName = function getName() {
+ return this.name;
+ };
+
+ Jedi.prototype.toString = function toString() {
+ return 'Jedi - ' + this.getName();
+ };
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## 事件
+
+ - 当给事件附加数据时,传入一个哈希而不是原始值,这可以让后面的贡献者加入更多数据到事件数据里而不用找出并更新那个事件的事件处理器
+
+ ```js
+ // bad
+ $(this).trigger('listingUpdated', listing.id);
+
+ ...
+
+ $(this).on('listingUpdated', function(e, listingId) {
+ // do something with listingId
+ });
+ ```
+
+ 更好:
+
+ ```js
+ // good
+ $(this).trigger('listingUpdated', { listingId : listing.id });
+
+ ...
+
+ $(this).on('listingUpdated', function(e, data) {
+ // do something with data.listingId
+ });
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## 模块
+
+ - 模块应该以 `!` 开始,这保证了如果一个有问题的模块忘记包含最后的分号在合并后不会出现错误
+ - 这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致
+ - 加入一个名为noConflict()的方法来设置导出的模块为之前的版本并返回它
+ - 总是在模块顶部声明 `'use strict';`
+
+ ```javascript
+ // fancyInput/fancyInput.js
+
+ !function(global) {
+ 'use strict';
+
+ var previousFancyInput = global.FancyInput;
+
+ function FancyInput(options) {
+ this.options = options || {};
+ }
+
+ FancyInput.noConflict = function noConflict() {
+ global.FancyInput = previousFancyInput;
+ return FancyInput;
+ };
+
+ global.FancyInput = FancyInput;
+ }(this);
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## jQuery
+
+ - 缓存jQuery查询
+
+ ```javascript
+ // bad
+ function setSidebar() {
+ $('.sidebar').hide();
+
+ // ...stuff...
+
+ $('.sidebar').css({
+ 'background-color': 'pink'
+ });
+ }
+
+ // good
+ function setSidebar() {
+ var $sidebar = $('.sidebar');
+ $sidebar.hide();
+
+ // ...stuff...
+
+ $sidebar.css({
+ 'background-color': 'pink'
+ });
+ }
+ ```
+
+ - 对DOM查询使用级联的 `$('.sidebar ul')` 或 `$('.sidebar ul')`,[jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)
+ - 对有作用域的jQuery对象查询使用 `find`
+
+ ```javascript
+ // bad
+ $('.sidebar', 'ul').hide();
+
+ // bad
+ $('.sidebar').find('ul').hide();
+
+ // good
+ $('.sidebar ul').hide();
+
+ // good
+ $('.sidebar > ul').hide();
+
+ // good (slower)
+ $sidebar.find('ul');
+
+ // good (faster)
+ $($sidebar[0]).find('ul');
+ ```
+
+ **[[⬆]](#TOC)**
+
+
+## ECMAScript 5兼容性
+
+ - 参考[Kangax](https://twitter.com/kangax/)的 ES5 [compatibility table](http://kangax.github.com/es5-compat-table/)
+
+ **[[⬆]](#TOC)**
+
+
+
+## 性能
+
+ - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/)
+ - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2)
+ - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost)
+ - [Bang Function](http://jsperf.com/bang-function)
+ - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13)
+ - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text)
+ - [Long String Concatenation](http://jsperf.com/ya-string-concat)
+ - Loading...
+
+ **[[⬆]](#TOC)**
+
+
+## 资源
+
+**Read This**
+
+ - [Annotated ECMAScript 5.1](http://es5.github.com/)
+
+**其它规范**
+
+ - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml)
+ - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines)
+ - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/)
+
+**其它风格**
+
+ - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen
+ - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52)
+
+**阅读更多**
+
+ - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll
+
+**书籍**
+
+ - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford
+ - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov
+ - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz
+ - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders
+ - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas
+ - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw
+ - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig
+ - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch
+
+**博客**
+
+ - [Adam Lu](http://adamlu.com/)
+ - [DailyJS](http://dailyjs.com/)
+ - [JavaScript Weekly](http://javascriptweekly.com/)
+ - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/)
+ - [Bocoup Weblog](http://weblog.bocoup.com/)
+ - [Adequately Good](http://www.adequatelygood.com/)
+ - [NCZOnline](http://www.nczonline.net/)
+ - [Perfection Kills](http://perfectionkills.com/)
+ - [Ben Alman](http://benalman.com/)
+ - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/)
+ - [Dustin Diaz](http://dustindiaz.com/)
+ - [nettuts](http://net.tutsplus.com/?s=javascript)
+
+ **[[⬆]](#TOC)**
+
+## 哪些人在使用
+
+ 这是一些使用这个风格规范的组织,给我们发pull request或打开一个问题,我们会把你加到列表中。
+
+ - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript)
+ - **American Insitutes for Research**: [AIRAST/javascript](https://github.com/AIRAST/javascript)
+ - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript)
+ - **GeneralElectric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript)
+ - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style)
+ - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript)
+ - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript)
+ - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript)
+ - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript)
+ - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript)
+ - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide)
+ - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript)
+ - **Userify**: [userify/javascript](https://github.com/userify/javascript)
+ - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript)
+ - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript)
+
+## 翻译
+
+ 这个风格规范也有其它语言版本:
+
+ - :de: **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide)
+ - :jp: **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide)
+ - :br: **Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide)
+ - :cn: **Chinese**: [adamlu/javascript-style-guide](https://github.com/adamlu/javascript-style-guide)
+
+## JavaScript风格指南
+
+ - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide)
+
+## 贡献者
+
+ - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors)
+
+
+## 许可
+
+(The MIT License)
+
+Copyright (c) 2012 Airbnb
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**[[⬆]](#TOC)**
+
+# };
diff --git a/docs/es5_zh-cn_v3.md b/docs/es5_zh-cn_v3.md
new file mode 100644
index 0000000000..20214dab68
--- /dev/null
+++ b/docs/es5_zh-cn_v3.md
@@ -0,0 +1,1767 @@
+
+source: https://github.com/sivan/javascript-style-guide/tree/master/es5
+
+# Airbnb JavaScript Style Guide() {
+
+*用更合理的方式写 JavaScript*
+
+#### ES5 规范相对于 ES6,要求全是用尾分号
+
+针对老项目,注意以下细节(我的老项目的暂定处理方案)
+
+- 尾分号全要 "semi": ["error", "always"],
+- 不做要求:"use strict" 使用严格模式 "strict": 0,
+- 空白行使用一次最多两行
+- 不做要求:匿名函数必须命名 "func-names": 0,
+- 不做要求:函数圆括号之前有一个空格 "space-before-function-paren": 0,
+- 不做要求:语句块之前有一个空格 "space-before-blocks": 0,
+- 不做要求:圆括号内侧不能有紧邻空格 "space-in-parens": 0,
+- 不做要求:对象字面量属性名称使用引号(但要求使用一致的引号: 有 or 无) "quote-props": ["error", "consistent"],
+- 不做要求:强制使用一致的反勾号、双引号或单引号 "quotes": 0,
+- 暂不做要求:使用 === 和 !== 而非 == 和 != "eqeqeq": 0,
+- 暂定:强制行的最大长度(现在显示器越发大了,可以暂定160) "max-len": ["error", { "code": 160 }],
+- 暂不做要求:码块的开始和结尾是否应该留一个空行 "padded-blocks": 0,
+- 暂不做要求:关键字keyword前后是否需要留一个空格 "keyword-spacing": 0,
+
+老项目常见问题:
+
+- 变量及函数命名未使用驼峰式 "camelcase": 2,
+- 禁止对函数参数再赋值 "no-param-reassign": ["error", { "props": false }],
+- 禁止在返回语句中赋值,除非用圆括号括起来 "no-return-assign": 2,
+
+## 目录
+
+ 1. [类型](#types)
+ 1. [对象](#objects)
+ 1. [数组](#arrays)
+ 1. [字符串](#strings)
+ 1. [函数](#functions)
+ 1. [属性](#properties)
+ 1. [变量](#variables)
+ 1. [提升](#hoisting)
+ 1. [比较运算符 & 等号](#comparison-operators--equality)
+ 1. [块](#blocks)
+ 1. [注释](#comments)
+ 1. [空白](#whitespace)
+ 1. [逗号](#commas)
+ 1. [分号](#semicolons)
+ 1. [类型转化](#type-casting--coercion)
+ 1. [命名规则](#naming-conventions)
+ 1. [存取器](#accessors)
+ 1. [构造函数](#constructors)
+ 1. [事件](#events)
+ 1. [模块](#modules)
+ 1. [jQuery](#jquery)
+ 1. [ECMAScript 5 兼容性](#ecmascript-5-compatibility)
+ 1. [测试](#testing)
+ 1. [性能](#performance)
+ 1. [资源](#resources)
+ 1. [谁在使用](#in-the-wild)
+ 1. [翻译](#translation)
+ 1. [JavaScript 风格指南说明](#the-javascript-style-guide-guide)
+ 1. [与我们讨论 JavaScript](#chat-with-us-about-javascript)
+ 1. [贡献者](#contributors)
+ 1. [许可](#license)
+
+## 类型
+
+ - **原始值**: 存取直接作用于它自身。
+
+ + `string`
+ + `number`
+ + `boolean`
+ + `null`
+ + `undefined`
+
+ ```javascript
+ var foo = 1;
+ var bar = foo;
+
+ bar = 9;
+
+ console.log(foo, bar); // => 1, 9
+ ```
+ - **复杂类型**: 存取时作用于它自身值的引用。
+
+ + `object`
+ + `array`
+ + `function`
+
+ ```javascript
+ var foo = [1, 2];
+ var bar = foo;
+
+ bar[0] = 9;
+
+ console.log(foo[0], bar[0]); // => 9, 9
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## 对象
+
+ - 使用直接量创建对象。
+
+ ```javascript
+ // bad
+ var item = new Object();
+
+ // good
+ var item = {};
+ ```
+
+ - 不要使用[保留字](http://es5.github.io/#x7.6.1)作为键名,它们在 IE8 下不工作。[更多信息](https://github.com/airbnb/javascript/issues/61)。
+
+ ```javascript
+ // bad
+ var superman = {
+ default: { clark: 'kent' },
+ private: true
+ };
+
+ // good
+ var superman = {
+ defaults: { clark: 'kent' },
+ hidden: true
+ };
+ ```
+
+ - 使用同义词替换需要使用的保留字。
+
+ ```javascript
+ // bad
+ var superman = {
+ class: 'alien'
+ };
+
+ // bad
+ var superman = {
+ klass: 'alien'
+ };
+
+ // good
+ var superman = {
+ type: 'alien'
+ };
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## 数组
+
+ - 使用直接量创建数组。
+
+ ```javascript
+ // bad
+ var items = new Array();
+
+ // good
+ var items = [];
+ ```
+
+ - 向数组增加元素时使用 Array#push 来替代直接赋值。
+
+ ```javascript
+ var someStack = [];
+
+
+ // bad
+ someStack[someStack.length] = 'abracadabra';
+
+ // good
+ someStack.push('abracadabra');
+ ```
+
+ - 当你需要拷贝数组时,使用 Array#slice。[jsPerf](http://jsperf.com/converting-arguments-to-an-array/7)
+
+ ```javascript
+ var len = items.length;
+ var itemsCopy = [];
+ var i;
+
+ // bad
+ for (i = 0; i < len; i++) {
+ itemsCopy[i] = items[i];
+ }
+
+ // good
+ itemsCopy = items.slice();
+ ```
+
+ - 使用 Array#slice 将类数组对象转换成数组。
+
+ ```javascript
+ function trigger() {
+ var args = Array.prototype.slice.call(arguments);
+ ...
+ }
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 字符串
+
+ - 使用单引号 `''` 包裹字符串。
+
+ ```javascript
+ // bad
+ var name = "Bob Parr";
+
+ // good
+ var name = 'Bob Parr';
+
+ // bad
+ var fullName = "Bob " + this.lastName;
+
+ // good
+ var fullName = 'Bob ' + this.lastName;
+ ```
+
+ - 超过 100 个字符的字符串应该使用连接符写成多行。
+ - 注:若过度使用,通过连接符连接的长字符串可能会影响性能。[jsPerf](http://jsperf.com/ya-string-concat) & [讨论](https://github.com/airbnb/javascript/issues/40).
+
+ ```javascript
+ // bad
+ var 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.';
+
+ // bad
+ var 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.';
+
+ // good
+ var 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.';
+ ```
+
+ - 程序化生成的字符串使用 Array#join 连接而不是使用连接符。尤其是 IE 下:[jsPerf](http://jsperf.com/string-vs-array-concat/2).
+
+ ```javascript
+ var items;
+ var messages;
+ var length;
+ var i;
+
+ messages = [{
+ state: 'success',
+ message: 'This one worked.'
+ }, {
+ state: 'success',
+ message: 'This one worked as well.'
+ }, {
+ state: 'error',
+ message: 'This one did not work.'
+ }];
+
+ length = messages.length;
+
+ // bad
+ function inbox(messages) {
+ items = '';
+
+ for (i = 0; i < length; i++) {
+ items += '- ' + messages[i].message + '
';
+ }
+
+ return items + '
';
+ }
+
+ // good
+ function inbox(messages) {
+ items = [];
+
+ for (i = 0; i < length; i++) {
+ // use direct assignment in this case because we're micro-optimizing.
+ items[i] = '' + messages[i].message + '';
+ }
+
+ return '';
+ }
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 函数
+
+ - 函数表达式:
+
+ ```javascript
+ // 匿名函数表达式
+ var anonymous = function() {
+ return true;
+ };
+
+ // 命名函数表达式
+ var named = function named() {
+ return true;
+ };
+
+ // 立即调用的函数表达式(IIFE)
+ (function () {
+ console.log('Welcome to the Internet. Please follow me.');
+ }());
+ ```
+
+ - 永远不要在一个非函数代码块(if、while 等)中声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但它们的解析表现不一致。
+ - **注:** ECMA-262 把 `块` 定义为一组语句。函数声明不是语句。[阅读对 ECMA-262 这个问题的说明](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97)。
+
+ ```javascript
+ // bad
+ if (currentUser) {
+ function test() {
+ console.log('Nope.');
+ }
+ }
+
+ // good
+ var test;
+ if (currentUser) {
+ test = function test() {
+ console.log('Yup.');
+ };
+ }
+ ```
+
+ - 永远不要把参数命名为 `arguments`。这将取代函数作用域内的 `arguments` 对象。
+
+ ```javascript
+ // bad
+ function nope(name, options, arguments) {
+ // ...stuff...
+ }
+
+ // good
+ function yup(name, options, args) {
+ // ...stuff...
+ }
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+
+## 属性
+
+ - 使用 `.` 来访问对象的属性。
+
+ ```javascript
+ var luke = {
+ jedi: true,
+ age: 28
+ };
+
+ // bad
+ var isJedi = luke['jedi'];
+
+ // good
+ var isJedi = luke.jedi;
+ ```
+
+ - 当通过变量访问属性时使用中括号 `[]`。
+
+ ```javascript
+ var luke = {
+ jedi: true,
+ age: 28
+ };
+
+ function getProp(prop) {
+ return luke[prop];
+ }
+
+ var isJedi = getProp('jedi');
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 变量
+
+ - 总是使用 `var` 来声明变量。不这么做将导致产生全局变量。我们要避免污染全局命名空间。
+
+ ```javascript
+ // bad
+ superPower = new SuperPower();
+
+ // good
+ var superPower = new SuperPower();
+ ```
+
+ - 使用 `var` 声明每一个变量。
+ 这样做的好处是增加新变量将变的更加容易,而且你永远不用再担心调换错 `;` 跟 `,`。
+
+ ```javascript
+ // bad
+ var items = getItems(),
+ goSportsTeam = true,
+ dragonball = 'z';
+
+ // bad
+ // (跟上面的代码比较一下,看看哪里错了)
+ var items = getItems(),
+ goSportsTeam = true;
+ dragonball = 'z';
+
+ // good
+ var items = getItems();
+ var goSportsTeam = true;
+ var dragonball = 'z';
+ ```
+
+ - 最后再声明未赋值的变量。当你需要引用前面的变量赋值时这将变的很有用。
+
+ ```javascript
+ // bad
+ var i, len, dragonball,
+ items = getItems(),
+ goSportsTeam = true;
+
+ // bad
+ var i;
+ var items = getItems();
+ var dragonball;
+ var goSportsTeam = true;
+ var len;
+
+ // good
+ var items = getItems();
+ var goSportsTeam = true;
+ var dragonball;
+ var length;
+ var i;
+ ```
+
+ - 在作用域顶部声明变量。这将帮你避免变量声明提升相关的问题。
+
+ ```javascript
+ // bad
+ function () {
+ test();
+ console.log('doing stuff..');
+
+ //..other stuff..
+
+ var name = getName();
+
+ if (name === 'test') {
+ return false;
+ }
+
+ return name;
+ }
+
+ // good
+ function () {
+ var name = getName();
+
+ test();
+ console.log('doing stuff..');
+
+ //..other stuff..
+
+ if (name === 'test') {
+ return false;
+ }
+
+ return name;
+ }
+
+ // bad - 不必要的函数调用
+ function () {
+ var name = getName();
+
+ if (!arguments.length) {
+ return false;
+ }
+
+ this.setFirstName(name);
+
+ return true;
+ }
+
+ // good
+ function () {
+ var name;
+
+ if (!arguments.length) {
+ return false;
+ }
+
+ name = getName();
+ this.setFirstName(name);
+
+ return true;
+ }
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 提升
+
+ - 变量声明会提升至作用域顶部,但赋值不会。
+
+ ```javascript
+ // 我们知道这样不能正常工作(假设这里没有名为 notDefined 的全局变量)
+ function example() {
+ console.log(notDefined); // => throws a ReferenceError
+ }
+
+ // 但由于变量声明提升的原因,在一个变量引用后再创建它的变量声明将可以正常工作。
+ // 注:变量赋值为 `true` 不会提升。
+ function example() {
+ console.log(declaredButNotAssigned); // => undefined
+ var declaredButNotAssigned = true;
+ }
+
+ // 解释器会把变量声明提升到作用域顶部,意味着我们的例子将被重写成:
+ function example() {
+ var declaredButNotAssigned;
+ console.log(declaredButNotAssigned); // => undefined
+ declaredButNotAssigned = true;
+ }
+ ```
+
+ - 匿名函数表达式会提升它们的变量名,但不会提升函数的赋值。
+
+ ```javascript
+ function example() {
+ console.log(anonymous); // => undefined
+
+ anonymous(); // => TypeError anonymous is not a function
+
+ var anonymous = function () {
+ console.log('anonymous function expression');
+ };
+ }
+ ```
+
+ - 命名函数表达式会提升变量名,但不会提升函数名或函数体。
+
+ ```javascript
+ function example() {
+ console.log(named); // => undefined
+
+ named(); // => TypeError named is not a function
+
+ superPower(); // => ReferenceError superPower is not defined
+
+ var named = function superPower() {
+ console.log('Flying');
+ };
+ }
+
+ // 当函数名跟变量名一样时,表现也是如此。
+ function example() {
+ console.log(named); // => undefined
+
+ named(); // => TypeError named is not a function
+
+ var named = function named() {
+ console.log('named');
+ }
+ }
+ ```
+
+ - 函数声明提升它们的名字和函数体。
+
+ ```javascript
+ function example() {
+ superPower(); // => Flying
+
+ function superPower() {
+ console.log('Flying');
+ }
+ }
+ ```
+
+ - 了解更多信息在 [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) by [Ben Cherry](http://www.adequatelygood.com/).
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+
+## 比较运算符 & 等号
+
+ - 优先使用 `===` 和 `!==` 而不是 `==` 和 `!=`.
+ - 条件表达式例如 `if` 语句通过抽象方法 `ToBoolean` 强制计算它们的表达式并且总是遵守下面的规则:
+
+ + **对象** 被计算为 **true**
+ + **Undefined** 被计算为 **false**
+ + **Null** 被计算为 **false**
+ + **布尔值** 被计算为 **布尔的值**
+ + **数字** 如果是 **+0、-0 或 NaN** 被计算为 **false**,否则为 **true**
+ + **字符串** 如果是空字符串 `''` 被计算为 **false**,否则为 **true**
+
+ ```javascript
+ if ([0]) {
+ // true
+ // 一个数组就是一个对象,对象被计算为 true
+ }
+ ```
+
+ - 使用快捷方式。
+
+ ```javascript
+ // bad
+ if (name !== '') {
+ // ...stuff...
+ }
+
+ // good
+ if (name) {
+ // ...stuff...
+ }
+
+ // bad
+ if (collection.length > 0) {
+ // ...stuff...
+ }
+
+ // good
+ if (collection.length) {
+ // ...stuff...
+ }
+ ```
+
+ - 了解更多信息在 [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll.
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 块
+
+ - 使用大括号包裹所有的多行代码块。
+
+ ```javascript
+ // bad
+ if (test)
+ return false;
+
+ // good
+ if (test) return false;
+
+ // good
+ if (test) {
+ return false;
+ }
+
+ // bad
+ function () { return false; }
+
+ // good
+ function () {
+ return false;
+ }
+ ```
+
+ - 如果通过 `if` 和 `else` 使用多行代码块,把 `else` 放在 `if` 代码块关闭括号的同一行。
+
+ ```javascript
+ // bad
+ if (test) {
+ thing1();
+ thing2();
+ }
+ else {
+ thing3();
+ }
+
+ // good
+ if (test) {
+ thing1();
+ thing2();
+ } else {
+ thing3();
+ }
+ ```
+
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 注释
+
+ - 使用 `/** ... */` 作为多行注释。包含描述、指定所有参数和返回值的类型和值。
+
+ ```javascript
+ // bad
+ // make() returns a new element
+ // based on the passed in tag name
+ //
+ // @param {String} tag
+ // @return {Element} element
+ function make(tag) {
+
+ // ...stuff...
+
+ return element;
+ }
+
+ // good
+ /**
+ * make() returns a new element
+ * based on the passed in tag name
+ *
+ * @param {String} tag
+ * @return {Element} element
+ */
+ function make(tag) {
+
+ // ...stuff...
+
+ return element;
+ }
+ ```
+
+ - 使用 `//` 作为单行注释。在评论对象上面另起一行使用单行注释。在注释前插入空行。
+
+ ```javascript
+ // bad
+ var active = true; // is current tab
+
+ // good
+ // is current tab
+ var active = true;
+
+ // bad
+ function getType() {
+ console.log('fetching type...');
+ // set the default type to 'no type'
+ var type = this.type || 'no type';
+
+ return type;
+ }
+
+ // good
+ function getType() {
+ console.log('fetching type...');
+
+ // set the default type to 'no type'
+ var type = this.type || 'no type';
+
+ return type;
+ }
+ ```
+
+ - 给注释增加 `FIXME` 或 `TODO` 的前缀可以帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。这将有别于常见的注释,因为它们是可操作的。使用 `FIXME -- need to figure this out` 或者 `TODO -- need to implement`。
+
+ - 使用 `// FIXME:` 标注问题。
+
+ ```javascript
+ function Calculator() {
+
+ // FIXME: shouldn't use a global here
+ total = 0;
+
+ return this;
+ }
+ ```
+
+ - 使用 `// TODO:` 标注问题的解决方式。
+
+ ```javascript
+ function Calculator() {
+
+ // TODO: total should be configurable by an options param
+ this.total = 0;
+
+ return this;
+ }
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 空白
+
+ - 使用 2 个空格作为缩进。
+
+ ```javascript
+ // bad
+ function () {
+ ∙∙∙∙var name;
+ }
+
+ // bad
+ function () {
+ ∙var name;
+ }
+
+ // good
+ function () {
+ ∙∙var name;
+ }
+ ```
+
+ - 在大括号前放一个空格。
+
+ ```javascript
+ // bad
+ function test(){
+ console.log('test');
+ }
+
+ // good
+ function test() {
+ console.log('test');
+ }
+
+ // bad
+ dog.set('attr',{
+ age: '1 year',
+ breed: 'Bernese Mountain Dog'
+ });
+
+ // good
+ dog.set('attr', {
+ age: '1 year',
+ breed: 'Bernese Mountain Dog'
+ });
+ ```
+
+ - 在控制语句(`if`、`while` 等)的小括号前放一个空格。在函数调用及声明中,不在函数的参数列表前加空格。
+
+ ```javascript
+ // bad
+ if(isJedi) {
+ fight ();
+ }
+
+ // good
+ if (isJedi) {
+ fight();
+ }
+
+ // bad
+ function fight () {
+ console.log ('Swooosh!');
+ }
+
+ // good
+ function fight() {
+ console.log('Swooosh!');
+ }
+ ```
+
+ - 使用空格把运算符隔开。
+
+ ```javascript
+ // bad
+ var x=y+5;
+
+ // good
+ var x = y + 5;
+ ```
+
+ - 在文件末尾插入一个空行。
+
+ ```javascript
+ // bad
+ (function (global) {
+ // ...stuff...
+ })(this);
+ ```
+
+ ```javascript
+ // bad
+ (function (global) {
+ // ...stuff...
+ })(this);↵
+ ↵
+ ```
+
+ ```javascript
+ // good
+ (function (global) {
+ // ...stuff...
+ })(this);↵
+ ```
+
+ - 在使用长方法链时进行缩进。使用前面的点 `.` 强调这是方法调用而不是新语句。
+
+ ```javascript
+ // bad
+ $('#items').find('.selected').highlight().end().find('.open').updateCount();
+
+ // bad
+ $('#items').
+ find('.selected').
+ highlight().
+ end().
+ find('.open').
+ updateCount();
+
+ // good
+ $('#items')
+ .find('.selected')
+ .highlight()
+ .end()
+ .find('.open')
+ .updateCount();
+
+ // bad
+ var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
+ .attr('width', (radius + margin) * 2).append('svg:g')
+ .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
+ .call(tron.led);
+
+ // good
+ var leds = stage.selectAll('.led')
+ .data(data)
+ .enter().append('svg:svg')
+ .classed('led', true)
+ .attr('width', (radius + margin) * 2)
+ .append('svg:g')
+ .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
+ .call(tron.led);
+ ```
+
+ - 在块末和新语句前插入空行。
+
+ ```javascript
+ // bad
+ if (foo) {
+ return bar;
+ }
+ return baz;
+
+ // good
+ if (foo) {
+ return bar;
+ }
+
+ return baz;
+
+ // bad
+ var obj = {
+ foo: function () {
+ },
+ bar: function () {
+ }
+ };
+ return obj;
+
+ // good
+ var obj = {
+ foo: function () {
+ },
+
+ bar: function () {
+ }
+ };
+
+ return obj;
+ ```
+
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## 逗号
+
+ - 行首逗号: **不需要**。
+
+ ```javascript
+ // bad
+ var story = [
+ once
+ , upon
+ , aTime
+ ];
+
+ // good
+ var story = [
+ once,
+ upon,
+ aTime
+ ];
+
+ // bad
+ var hero = {
+ firstName: 'Bob'
+ , lastName: 'Parr'
+ , heroName: 'Mr. Incredible'
+ , superPower: 'strength'
+ };
+
+ // good
+ var hero = {
+ firstName: 'Bob',
+ lastName: 'Parr',
+ heroName: 'Mr. Incredible',
+ superPower: 'strength'
+ };
+ ```
+
+ - 额外的行末逗号:**不需要**。这样做会在 IE6/7 和 IE9 怪异模式下引起问题。同样,多余的逗号在某些 ES3 的实现里会增加数组的长度。在 ES5 中已经澄清了 ([source](http://es5.github.io/#D)):
+
+ > Edition 5 clarifies the fact that a trailing comma at the end of an ArrayInitialiser does not add to the length of the array. This is not a semantic change from Edition 3 but some implementations may have previously misinterpreted this.
+
+ ```javascript
+ // bad
+ var hero = {
+ firstName: 'Kevin',
+ lastName: 'Flynn',
+ };
+
+ var heroes = [
+ 'Batman',
+ 'Superman',
+ ];
+
+ // good
+ var hero = {
+ firstName: 'Kevin',
+ lastName: 'Flynn'
+ };
+
+ var heroes = [
+ 'Batman',
+ 'Superman'
+ ];
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 分号
+
+ - **使用分号。**
+
+ ```javascript
+ // bad
+ (function () {
+ var name = 'Skywalker'
+ return name
+ })()
+
+ // good
+ (function () {
+ var name = 'Skywalker';
+ return name;
+ })();
+
+ // good (防止函数在两个 IIFE 合并时被当成一个参数
+ ;(function () {
+ var name = 'Skywalker';
+ return name;
+ })();
+ ```
+
+ [了解更多](http://stackoverflow.com/a/7365214/1712802).
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 类型转换
+
+ - 在语句开始时执行类型转换。
+ - 字符串:
+
+ ```javascript
+ // => this.reviewScore = 9;
+
+ // bad
+ var totalScore = this.reviewScore + '';
+
+ // good
+ var totalScore = '' + this.reviewScore;
+
+ // bad
+ var totalScore = '' + this.reviewScore + ' total score';
+
+ // good
+ var totalScore = this.reviewScore + ' total score';
+ ```
+
+ - 使用 `parseInt` 转换数字时总是带上类型转换的基数。
+
+ ```javascript
+ var inputValue = '4';
+
+ // bad
+ var val = new Number(inputValue);
+
+ // bad
+ var val = +inputValue;
+
+ // bad
+ var val = inputValue >> 0;
+
+ // bad
+ var val = parseInt(inputValue);
+
+ // good
+ var val = Number(inputValue);
+
+ // good
+ var val = parseInt(inputValue, 10);
+ ```
+
+ - 如果因为某些原因 `parseInt` 成为你所做的事的瓶颈而需要使用位操作解决[性能问题](http://jsperf.com/coercion-vs-casting/3)时,留个注释说清楚原因和你的目的。
+
+ ```javascript
+ // good
+ /**
+ * parseInt was the reason my code was slow.
+ * Bitshifting the String to coerce it to a
+ * Number made it a lot faster.
+ */
+ var val = inputValue >> 0;
+ ```
+
+ - **注:** 小心使用位操作运算符。数字会被当成 [64 位值](http://es5.github.io/#x4.3.19),但是位操作运算符总是返回 32 位的整数([source](http://es5.github.io/#x11.7))。位操作处理大于 32 位的整数值时还会导致意料之外的行为。[讨论](https://github.com/airbnb/javascript/issues/109)。最大的 32 位整数是 2,147,483,647:
+
+ ```javascript
+ 2147483647 >> 0 //=> 2147483647
+ 2147483648 >> 0 //=> -2147483648
+ 2147483649 >> 0 //=> -2147483647
+ ```
+
+ - 布尔:
+
+ ```javascript
+ var age = 0;
+
+ // bad
+ var hasAge = new Boolean(age);
+
+ // good
+ var hasAge = Boolean(age);
+
+ // good
+ var hasAge = !!age;
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 命名规则
+
+ - 避免单字母命名。命名应具备描述性。
+
+ ```javascript
+ // bad
+ function q() {
+ // ...stuff...
+ }
+
+ // good
+ function query() {
+ // ..stuff..
+ }
+ ```
+
+ - 使用驼峰式命名对象、函数和实例。
+
+ ```javascript
+ // bad
+ var OBJEcttsssss = {};
+ var this_is_my_object = {};
+ var o = {};
+ function c() {}
+
+ // good
+ var thisIsMyObject = {};
+ function thisIsMyFunction() {}
+ ```
+
+ - 使用帕斯卡式命名构造函数或类。
+
+ ```javascript
+ // bad
+ function user(options) {
+ this.name = options.name;
+ }
+
+ var bad = new user({
+ name: 'nope'
+ });
+
+ // good
+ function User(options) {
+ this.name = options.name;
+ }
+
+ var good = new User({
+ name: 'yup'
+ });
+ ```
+
+ - 不要使用下划线前/后缀。
+
+ > 为什么?JavaScript 并没有私有属性或私有方法的概念。虽然使用下划线是表示「私有」的一种共识,但实际上这些属性是完全公开的,它本身就是你公共接口的一部分。这种习惯或许会导致开发者错误的认为改动它不会造成破坏或者不需要去测试。长话短说:如果你想要某处为「私有」,它必须不能是显式提出的。
+
+ ```javascript
+ // bad
+ this.__firstName__ = 'Panda';
+ this.firstName_ = 'Panda';
+ this._firstName = 'Panda';
+
+ // good
+ this.firstName = 'Panda';
+ ```
+
+ - 不要保存 `this` 的引用。使用 Function#bind。
+
+ ```javascript
+ // bad
+ function () {
+ var self = this;
+ return function () {
+ console.log(self);
+ };
+ }
+
+ // bad
+ function () {
+ var that = this;
+ return function () {
+ console.log(that);
+ };
+ }
+
+ // bad
+ function () {
+ var _this = this;
+ return function () {
+ console.log(_this);
+ };
+ }
+
+ // good
+ function () {
+ return function () {
+ console.log(this);
+ }.bind(this);
+ }
+ ```
+
+ - 给函数命名。这在做堆栈轨迹时很有帮助。
+
+ ```javascript
+ // bad
+ var log = function (msg) {
+ console.log(msg);
+ };
+
+ // good
+ var log = function log(msg) {
+ console.log(msg);
+ };
+ ```
+
+ - **注:** IE8 及以下版本对命名函数表达式的处理有些怪异。了解更多信息到 [http://kangax.github.io/nfe/](http://kangax.github.io/nfe/)。
+
+ - 如果你的文件导出一个类,你的文件名应该与类名完全相同。
+ ```javascript
+ // file contents
+ class CheckBox {
+ // ...
+ }
+ module.exports = CheckBox;
+
+ // in some other file
+ // bad
+ var CheckBox = require('./checkBox');
+
+ // bad
+ var CheckBox = require('./check_box');
+
+ // good
+ var CheckBox = require('./CheckBox');
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 存取器
+
+ - 属性的存取函数不是必须的。
+ - 如果你需要存取函数时使用 `getVal()` 和 `setVal('hello')`。
+
+ ```javascript
+ // bad
+ dragon.age();
+
+ // good
+ dragon.getAge();
+
+ // bad
+ dragon.age(25);
+
+ // good
+ dragon.setAge(25);
+ ```
+
+ - 如果属性是布尔值,使用 `isVal()` 或 `hasVal()`。
+
+ ```javascript
+ // bad
+ if (!dragon.age()) {
+ return false;
+ }
+
+ // good
+ if (!dragon.hasAge()) {
+ return false;
+ }
+ ```
+
+ - 创建 get() 和 set() 函数是可以的,但要保持一致。
+
+ ```javascript
+ function Jedi(options) {
+ options || (options = {});
+ var lightsaber = options.lightsaber || 'blue';
+ this.set('lightsaber', lightsaber);
+ }
+
+ Jedi.prototype.set = function set(key, val) {
+ this[key] = val;
+ };
+
+ Jedi.prototype.get = function get(key) {
+ return this[key];
+ };
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 构造函数
+
+ - 给对象原型分配方法,而不是使用一个新对象覆盖原型。覆盖原型将导致继承出现问题:重设原型将覆盖原有原型!
+
+ ```javascript
+ function Jedi() {
+ console.log('new jedi');
+ }
+
+ // bad
+ Jedi.prototype = {
+ fight: function fight() {
+ console.log('fighting');
+ },
+
+ block: function block() {
+ console.log('blocking');
+ }
+ };
+
+ // good
+ Jedi.prototype.fight = function fight() {
+ console.log('fighting');
+ };
+
+ Jedi.prototype.block = function block() {
+ console.log('blocking');
+ };
+ ```
+
+ - 方法可以返回 `this` 来实现方法链式使用。
+
+ ```javascript
+ // bad
+ Jedi.prototype.jump = function jump() {
+ this.jumping = true;
+ return true;
+ };
+
+ Jedi.prototype.setHeight = function setHeight(height) {
+ this.height = height;
+ };
+
+ var luke = new Jedi();
+ luke.jump(); // => true
+ luke.setHeight(20); // => undefined
+
+ // good
+ Jedi.prototype.jump = function jump() {
+ this.jumping = true;
+ return this;
+ };
+
+ Jedi.prototype.setHeight = function setHeight(height) {
+ this.height = height;
+ return this;
+ };
+
+ var luke = new Jedi();
+
+ luke.jump()
+ .setHeight(20);
+ ```
+
+
+ - 写一个自定义的 `toString()` 方法是可以的,但是确保它可以正常工作且不会产生副作用。
+
+ ```javascript
+ function Jedi(options) {
+ options || (options = {});
+ this.name = options.name || 'no name';
+ }
+
+ Jedi.prototype.getName = function getName() {
+ return this.name;
+ };
+
+ Jedi.prototype.toString = function toString() {
+ return 'Jedi - ' + this.getName();
+ };
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 事件
+
+ - 当给事件附加数据时(无论是 DOM 事件还是私有事件),传入一个哈希而不是原始值。这样可以让后面的贡献者增加更多数据到事件数据而无需找出并更新事件的每一个处理器。例如,不好的写法:
+
+ ```js
+ // bad
+ $(this).trigger('listingUpdated', listing.id);
+
+ ...
+
+ $(this).on('listingUpdated', function (e, listingId) {
+ // do something with listingId
+ });
+ ```
+
+ 更好的写法:
+
+ ```js
+ // good
+ $(this).trigger('listingUpdated', { listingId : listing.id });
+
+ ...
+
+ $(this).on('listingUpdated', function (e, data) {
+ // do something with data.listingId
+ });
+ ```
+
+ **[⬆ 回到顶部](#table-of-contents)**
+
+
+## 模块
+
+ - 模块应该以 `!` 开始。这样确保了当一个不好的模块忘记包含最后的分号时,在合并代码到生产环境后不会产生错误。[详细说明](https://github.com/airbnb/javascript/issues/44#issuecomment-13063933)
+ - 文件应该以驼峰式命名,并放在同名的文件夹里,且与导出的名字一致。
+ - 增加一个名为 `noConflict()` 的方法来设置导出的模块为前一个版本并返回它。
+ - 永远在模块顶部声明 `'use strict';`。
+
+ ```javascript
+ // fancyInput/fancyInput.js
+
+ !function (global) {
+ 'use strict';
+
+ var previousFancyInput = global.FancyInput;
+
+ function FancyInput(options) {
+ this.options = options || {};
+ }
+
+ FancyInput.noConflict = function noConflict() {
+ global.FancyInput = previousFancyInput;
+ return FancyInput;
+ };
+
+ global.FancyInput = FancyInput;
+ }(this);
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## jQuery
+
+ - 使用 `$` 作为存储 jQuery 对象的变量名前缀。
+
+ ```javascript
+ // bad
+ var sidebar = $('.sidebar');
+
+ // good
+ var $sidebar = $('.sidebar');
+ ```
+
+ - 缓存 jQuery 查询。
+
+ ```javascript
+ // bad
+ function setSidebar() {
+ $('.sidebar').hide();
+
+ // ...stuff...
+
+ $('.sidebar').css({
+ 'background-color': 'pink'
+ });
+ }
+
+ // good
+ function setSidebar() {
+ var $sidebar = $('.sidebar');
+ $sidebar.hide();
+
+ // ...stuff...
+
+ $sidebar.css({
+ 'background-color': 'pink'
+ });
+ }
+ ```
+
+ - 对 DOM 查询使用层叠 `$('.sidebar ul')` 或 父元素 > 子元素 `$('.sidebar > ul')`。 [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)
+ - 对有作用域的 jQuery 对象查询使用 `find`。
+
+ ```javascript
+ // bad
+ $('ul', '.sidebar').hide();
+
+ // bad
+ $('.sidebar').find('ul').hide();
+
+ // good
+ $('.sidebar ul').hide();
+
+ // good
+ $('.sidebar > ul').hide();
+
+ // good
+ $sidebar.find('ul').hide();
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## ECMAScript 5 兼容性
+
+ - 参考 [Kangax](https://twitter.com/kangax/) 的 ES5 [兼容表](http://kangax.github.com/es5-compat-table/).
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 测试
+
+ - **Yup.**
+
+ ```javascript
+ function () {
+ return true;
+ }
+ ```
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 性能
+
+ - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/)
+ - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2)
+ - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost)
+ - [Bang Function](http://jsperf.com/bang-function)
+ - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13)
+ - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text)
+ - [Long String Concatenation](http://jsperf.com/ya-string-concat)
+ - Loading...
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+
+## 资源
+
+
+**推荐阅读**
+
+ - [Annotated ECMAScript 5.1](http://es5.github.com/)
+
+**工具**
+
+ - Code Style Linters
+ + [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/.jshintrc)
+ + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json)
+
+**其它风格指南**
+
+ - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml)
+ - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines)
+ - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/)
+ - [JavaScript Standard Style](https://github.com/feross/standard)
+
+**其它风格**
+
+ - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen
+ - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen
+ - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun
+ - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman
+
+**进一步阅读**
+
+ - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll
+ - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer
+ - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz
+ - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban
+ - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock
+
+**书籍**
+
+ - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford
+ - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov
+ - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz
+ - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders
+ - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas
+ - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw
+ - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig
+ - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch
+ - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault
+ - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg
+ - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
+ - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon
+ - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov
+ - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman
+ - [Eloquent JavaScript](http://eloquentjavascript.net) - Marijn Haverbeke
+ - [You Don't Know JS](https://github.com/getify/You-Dont-Know-JS) - Kyle Simpson
+
+**博客**
+
+ - [DailyJS](http://dailyjs.com/)
+ - [JavaScript Weekly](http://javascriptweekly.com/)
+ - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/)
+ - [Bocoup Weblog](http://weblog.bocoup.com/)
+ - [Adequately Good](http://www.adequatelygood.com/)
+ - [NCZOnline](http://www.nczonline.net/)
+ - [Perfection Kills](http://perfectionkills.com/)
+ - [Ben Alman](http://benalman.com/)
+ - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/)
+ - [Dustin Diaz](http://dustindiaz.com/)
+ - [nettuts](http://net.tutsplus.com/?s=javascript)
+
+**播客**
+
+ - [JavaScript Jabber](http://devchat.tv/js-jabber/)
+
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+## 谁在使用
+
+ 这是一个使用本风格指南的组织列表。给我们发 pull request 或开一个 issue 让我们将你增加到列表上。
+
+ - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript)
+ - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript)
+ - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript)
+ - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript)
+ - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript)
+ - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript)
+ - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide)
+ - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript)
+ - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript)
+ - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide)
+ - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript)
+ - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide)
+ - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript)
+ - **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript)
+ - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style)
+ - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript)
+ - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript)
+ - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide)
+ - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript)
+ - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions)
+ - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript)
+ - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/javascript)
+ - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript)
+ - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript)
+ - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript)
+ - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript)
+ - **Muber**: [muber/javascript](https://github.com/muber/javascript)
+ - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript)
+ - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript)
+ - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript)
+ - **Nordic Venture Family**: [CodeDistillery/javascript](https://github.com/CodeDistillery/javascript)
+ - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript)
+ - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript)
+ - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide)
+ - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript)
+ - **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide)
+ - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide)
+ - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide)
+ - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript)
+ - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/javascript)
+ - **Super**: [SuperJobs/javascript](https://github.com/SuperJobs/javascript)
+ - **SysGarage**: [sysgarage/javascript-style-guide](https://github.com/sysgarage/javascript-style-guide)
+ - **Target**: [target/javascript](https://github.com/target/javascript)
+ - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript)
+ - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript)
+ - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide)
+ - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript)
+ - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript)
+ - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript)
+
+## 翻译
+
+ 这份风格指南也提供了其它语言的版本:
+
+ -  **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide)
+ -  **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript)
+ -  **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide)
+ -  **Chinese(Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript)
+ -  **Chinese(Simplified)**: [sivan/javascript](https://github.com/sivan/javascript)
+ -  **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide)
+ -  **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide)
+ -  **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide)
+ -  **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide)
+ -  **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide)
+ -  **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript)
+ -  **Russian**: [uprock/javascript](https://github.com/uprock/javascript)
+ -  **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide)
+ -  **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide)
+
+## JavaScript 风格指南说明
+
+ - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide)
+
+## 与我们讨论 JavaScript
+
+ - Find us on [gitter](https://gitter.im/airbnb/javascript).
+
+## 贡献者
+
+ - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors)
+
+
+## 许可
+
+(The MIT License)
+
+Copyright (c) 2014 Airbnb
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**[⬆ 回到顶部](#table-of-contents)**
+
+# };
diff --git a/docs/es6.test.js b/docs/es6.test.js
new file mode 100644
index 0000000000..8fab136aa1
--- /dev/null
+++ b/docs/es6.test.js
@@ -0,0 +1,107 @@
+
+// ES6 代码规范练习场
+
+// 为便于测试,关闭部分规则检测
+/* eslint no-unused-vars: 0, no-console: 0, prefer-const: 0, */
+
+// [类型](#types)
+// 使用 let const 替代 var
+var type11 = 123
+var type2 = 'hello'
+
+const type3 = 123
+let type4 = 123
+// type4 = 456
+const type5 = 'hello'
+
+const type121 = [1, 2]
+const type122 = type121
+type122[0] = 9
+
+console.log(type122[0], type122[0])
+
+
+// [引用](#references)
+
+
+// [对象](#objects)
+
+
+// [数组](#arrays)
+
+
+// [解构](#destructuring)
+
+
+// [字符串](#strings)
+
+
+// [函数](#functions)
+(function anonymous() {
+ // bad
+ const original = { a: 1, b: 2 }
+ const copy = Object.assign({}, original, { c: 3 })
+ console.log(copy)
+})()
+
+(function anonymous() {
+ // bad
+ const original = { a: 1, b: 2 }
+ const copy = { ...original, c: 3 }
+ // const { ...copy } = original
+ console.log(copy)
+})()
+
+
+// [箭头函数](#arrow-functions)
+
+
+// [类 & 构造函数](#classes--constructors)
+
+
+// [模块](#modules)
+
+
+// [Iterators and Generators](#iterators-and-generators)
+
+
+// [属性](#properties)
+
+
+// [变量](#variables)
+
+
+// [提升](#hoisting)
+
+
+// [比较运算符 & 等号](#comparison-operators--equality)
+
+
+// [代码块](#blocks)
+
+
+// [注释](#comments)
+
+
+// [空白](#whitespace)
+
+
+// [逗号](#commas)
+
+
+// [分号](#semicolons)
+
+
+// [类型转换](#type-casting--coercion)
+
+
+// [命名规则](#naming-conventions)
+
+
+// [存取器](#accessors)
+
+
+// [事件](#events)
+
+
+// [jQuery](#jquery)
diff --git a/docs/es6_zh-cn_v1.md b/docs/es6_zh-cn_v1.md
new file mode 100644
index 0000000000..9709f373da
--- /dev/null
+++ b/docs/es6_zh-cn_v1.md
@@ -0,0 +1,2157 @@
+
+source: https://github.com/yuche/javascript
+
+[](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+# Airbnb JavaScript Style Guide() {
+
+**用更合理的方式写 JavaScript**
+
+ES5 的编码规范请查看[版本一](https://github.com/sivan/javascript-style-guide/blob/master/es5/README.md),[版本二](https://github.com/adamlu/javascript-style-guide)。
+
+翻译自 [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) 。
+
+
+## 目录
+
+ 1. [类型](#types)
+ 1. [引用](#references)
+ 1. [对象](#objects)
+ 1. [数组](#arrays)
+ 1. [解构](#destructuring)
+ 1. [字符串](#strings)
+ 1. [函数](#functions)
+ 1. [箭头函数](#arrow-functions)
+ 1. [构造函数](#constructors)
+ 1. [模块](#modules)
+ 1. [Iterators & Generators ](#iterators-and-generators)
+ 1. [属性](#properties)
+ 1. [变量](#variables)
+ 1. [提升](#hoisting)
+ 1. [比较运算符 & 等号](#comparison-operators--equality)
+ 1. [代码块](#blocks)
+ 1. [注释](#comments)
+ 1. [空白](#whitespace)
+ 1. [逗号](#commas)
+ 1. [分号](#semicolons)
+ 1. [类型转换](#type-casting--coercion)
+ 1. [命名规则](#naming-conventions)
+ 1. [存取器](#accessors)
+ 1. [事件](#events)
+ 1. [jQuery](#jquery)
+ 1. [ECMAScript 5 兼容性](#ecmascript-5-compatibility)
+ 1. [ECMAScript 6 编码规范](#ecmascript-6-styles)
+ 1. [测试](#testing)
+ 1. [性能](#performance)
+ 1. [资源](#resources)
+ 1. [使用人群](#in-the-wild)
+ 1. [翻译](#translation)
+ 1. [JavaScript 编码规范说明](#the-javascript-style-guide-guide)
+ 1. [一起来讨论 JavaScript](#chat-with-us-about-javascript)
+ 1. [Contributors](#contributors)
+ 1. [License](#license)
+
+
+## 类型
+
+ - [1.1](#1.1) **基本类型**: 直接存取基本类型。
+
+ + `字符串`
+ + `数值`
+ + `布尔类型`
+ + `null`
+ + `undefined`
+
+ ```javascript
+ const foo = 1;
+ let bar = foo;
+
+ bar = 9;
+
+ console.log(foo, bar); // => 1, 9
+ ```
+ - [1.2](#1.2) **复制类型**: 通过引用的方式存取复杂类型。
+
+ + `对象`
+ + `数组`
+ + `函数`
+
+ ```javascript
+ const foo = [1, 2];
+ const bar = foo;
+
+ bar[0] = 9;
+
+ console.log(foo[0], bar[0]); // => 9, 9
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 引用
+
+ - [2.1](#2.1) 对所有的引用使用 `const` ;不要使用 `var`。
+
+ > 为什么?这能确保你无法对引用重新赋值,也不会导致出现 bug 或难以理解。
+
+ ```javascript
+ // bad
+ var a = 1;
+ var b = 2;
+
+ // good
+ const a = 1;
+ const b = 2;
+ ```
+
+ - [2.2](#2.2) 如果你一定需要可变动的引用,使用 `let` 代替 `var`。
+
+ > 为什么?因为 `let` 是块级作用域,而 `var` 是函数作用域。
+
+ ```javascript
+ // bad
+ var count = 1;
+ if (true) {
+ count += 1;
+ }
+
+ // good, use the let.
+ let count = 1;
+ if (true) {
+ count += 1;
+ }
+ ```
+
+ - [2.3](#2.3) 注意 `let` 和 `const` 都是块级作用域。
+
+ ```javascript
+ // const 和 let 只存在于它们被定义的区块内。
+ {
+ let a = 1;
+ const b = 1;
+ }
+ console.log(a); // ReferenceError
+ console.log(b); // ReferenceError
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 对象
+
+ - [3.1](#3.1) 使用字面值创建对象。
+
+ ```javascript
+ // bad
+ const item = new Object();
+
+ // good
+ const item = {};
+ ```
+
+ - [3.2](#3.2) 如果你的代码在浏览器环境下执行,别使用 [保留字](http://es5.github.io/#x7.6.1) 作为键值。这样的话在 IE8 不会运行。 [更多信息](https://github.com/airbnb/javascript/issues/61)。 但在 ES6 模块和服务器端中使用没有问题。
+
+ ```javascript
+ // bad
+ const superman = {
+ default: { clark: 'kent' },
+ private: true,
+ };
+
+ // good
+ const superman = {
+ defaults: { clark: 'kent' },
+ hidden: true,
+ };
+ ```
+
+ - [3.3](#3.3) 使用同义词替换需要使用的保留字。
+
+ ```javascript
+ // bad
+ const superman = {
+ class: 'alien',
+ };
+
+ // bad
+ const superman = {
+ klass: 'alien',
+ };
+
+ // good
+ const superman = {
+ type: 'alien',
+ };
+ ```
+
+
+ - [3.4](#3.4) 创建有动态属性名的对象时,使用可被计算的属性名称。
+
+ > 为什么?因为这样可以让你在一个地方定义所有的对象属性。
+
+ ```javascript
+ function getKey(k) {
+ return `a key named ${k}`;
+ }
+
+ // bad
+ const obj = {
+ id: 5,
+ name: 'San Francisco',
+ };
+ obj[getKey('enabled')] = true;
+
+ // good
+ const obj = {
+ id: 5,
+ name: 'San Francisco',
+ [getKey('enabled')]: true,
+ };
+ ```
+
+
+ - [3.5](#3.5) 使用对象方法的简写。
+
+ ```javascript
+ // bad
+ const atom = {
+ value: 1,
+
+ addValue: function (value) {
+ return atom.value + value;
+ },
+ };
+
+ // good
+ const atom = {
+ value: 1,
+
+ addValue(value) {
+ return atom.value + value;
+ },
+ };
+ ```
+
+
+ - [3.6](#3.6) 使用对象属性值的简写。
+
+ > 为什么?因为这样更短更有描述性。
+
+ ```javascript
+ const lukeSkywalker = 'Luke Skywalker';
+
+ // bad
+ const obj = {
+ lukeSkywalker: lukeSkywalker,
+ };
+
+ // good
+ const obj = {
+ lukeSkywalker,
+ };
+ ```
+
+ - [3.7](#3.7) 在对象属性声明前把简写的属性分组。
+
+ > 为什么?因为这样能清楚地看出哪些属性使用了简写。
+
+ ```javascript
+ const anakinSkywalker = 'Anakin Skywalker';
+ const lukeSkywalker = 'Luke Skywalker';
+
+ // bad
+ const obj = {
+ episodeOne: 1,
+ twoJedisWalkIntoACantina: 2,
+ lukeSkywalker,
+ episodeThree: 3,
+ mayTheFourth: 4,
+ anakinSkywalker,
+ };
+
+ // good
+ const obj = {
+ lukeSkywalker,
+ anakinSkywalker,
+ episodeOne: 1,
+ twoJedisWalkIntoACantina: 2,
+ episodeThree: 3,
+ mayTheFourth: 4,
+ };
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 数组
+
+ - [4.1](#4.1) 使用字面值创建数组。
+
+ ```javascript
+ // bad
+ const items = new Array();
+
+ // good
+ const items = [];
+ ```
+
+ - [4.2](#4.2) 向数组添加元素时使用 Arrary#push 替代直接赋值。
+
+ ```javascript
+ const someStack = [];
+
+
+ // bad
+ someStack[someStack.length] = 'abracadabra';
+
+ // good
+ someStack.push('abracadabra');
+ ```
+
+
+ - [4.3](#4.3) 使用拓展运算符 `...` 复制数组。
+
+ ```javascript
+ // bad
+ const len = items.length;
+ const itemsCopy = [];
+ let i;
+
+ for (i = 0; i < len; i++) {
+ itemsCopy[i] = items[i];
+ }
+
+ // good
+ const itemsCopy = [...items];
+ ```
+ - [4.4](#4.4) 使用 Array#from 把一个类数组对象转换成数组。
+
+ ```javascript
+ const foo = document.querySelectorAll('.foo');
+ const nodes = Array.from(foo);
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 解构
+
+ - [5.1](#5.1) 使用解构存取和使用多属性对象。
+
+ > 为什么?因为解构能减少临时引用属性。
+
+ ```javascript
+ // bad
+ function getFullName(user) {
+ const firstName = user.firstName;
+ const lastName = user.lastName;
+
+ return `${firstName} ${lastName}`;
+ }
+
+ // good
+ function getFullName(obj) {
+ const { firstName, lastName } = obj;
+ return `${firstName} ${lastName}`;
+ }
+
+ // best
+ function getFullName({ firstName, lastName }) {
+ return `${firstName} ${lastName}`;
+ }
+ ```
+
+ - [5.2](#5.2) 对数组使用解构赋值。
+
+ ```javascript
+ const arr = [1, 2, 3, 4];
+
+ // bad
+ const first = arr[0];
+ const second = arr[1];
+
+ // good
+ const [first, second] = arr;
+ ```
+
+ - [5.3](#5.3) 需要回传多个值时,使用对象解构,而不是数组解构。
+ > 为什么?增加属性或者改变排序不会改变调用时的位置。
+
+ ```javascript
+ // bad
+ function processInput(input) {
+ // then a miracle occurs
+ return [left, right, top, bottom];
+ }
+
+ // 调用时需要考虑回调数据的顺序。
+ const [left, __, top] = processInput(input);
+
+ // good
+ function processInput(input) {
+ // then a miracle occurs
+ return { left, right, top, bottom };
+ }
+
+ // 调用时只选择需要的数据
+ const { left, right } = processInput(input);
+ ```
+
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## Strings
+
+ - [6.1](#6.1) 字符串使用单引号 `''` 。
+
+ ```javascript
+ // bad
+ const name = "Capt. Janeway";
+
+ // good
+ const name = 'Capt. Janeway';
+ ```
+
+ - [6.2](#6.2) 字符串超过 80 个字节应该使用字符串连接号换行。
+ - [6.3](#6.3) 注:过度使用字串连接符号可能会对性能造成影响。[jsPerf](http://jsperf.com/ya-string-concat) 和 [讨论](https://github.com/airbnb/javascript/issues/40).
+
+ ```javascript
+ // bad
+ 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.';
+
+ // bad
+ 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.';
+
+ // good
+ 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.';
+ ```
+
+
+ - [6.4](#6.4) 程序化生成字符串时,使用模板字符串代替字符串连接。
+
+ > 为什么?模板字符串更为简洁,更具可读性。
+
+ ```javascript
+ // bad
+ function sayHi(name) {
+ return 'How are you, ' + name + '?';
+ }
+
+ // bad
+ function sayHi(name) {
+ return ['How are you, ', name, '?'].join();
+ }
+
+ // good
+ function sayHi(name) {
+ return `How are you, ${name}?`;
+ }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 函数
+
+ - [7.1](#7.1) 使用函数声明代替函数表达式。
+
+ > 为什么?因为函数声明是可命名的,所以他们在调用栈中更容易被识别。此外,函数声明会把整个函数提升(hoisted),而函数表达式只会把函数的引用变量名提升。这条规则使得[箭头函数](#arrow-functions)可以取代函数表达式。
+
+ ```javascript
+ // bad
+ const foo = function () {
+ };
+
+ // good
+ function foo() {
+ }
+ ```
+
+ - [7.2](#7.2) 函数表达式:
+
+ ```javascript
+ // 立即调用的函数表达式 (IIFE)
+ (() => {
+ console.log('Welcome to the Internet. Please follow me.');
+ })();
+ ```
+
+ - [7.3](#7.3) 永远不要在一个非函数代码块(`if`、`while` 等)中声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但它们的解析表现不一致。
+ - [7.4](#7.4) **注意:** ECMA-262 把 `block` 定义为一组语句。函数声明不是语句。[阅读 ECMA-262 关于这个问题的说明](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97)。
+
+ ```javascript
+ // bad
+ if (currentUser) {
+ function test() {
+ console.log('Nope.');
+ }
+ }
+
+ // good
+ let test;
+ if (currentUser) {
+ test = () => {
+ console.log('Yup.');
+ };
+ }
+ ```
+
+ - [7.5](#7.5) 永远不要把参数命名为 `arguments`。这将取代原来函数作用域内的 `arguments` 对象。
+
+ ```javascript
+ // bad
+ function nope(name, options, arguments) {
+ // ...stuff...
+ }
+
+ // good
+ function yup(name, options, args) {
+ // ...stuff...
+ }
+ ```
+
+
+ - [7.6](#7.6) 不要使用 `arguments`。可以选择 rest 语法 `...` 替代。
+
+ > 为什么?使用 `...` 能明确你要传入的参数。另外 rest 参数是一个真正的数组,而 `arguments` 是一个类数组。
+
+ ```javascript
+ // bad
+ function concatenateAll() {
+ const args = Array.prototype.slice.call(arguments);
+ return args.join('');
+ }
+
+ // good
+ function concatenateAll(...args) {
+ return args.join('');
+ }
+ ```
+
+
+ - [7.7](#7.7) 直接给函数的参数指定默认值,不要使用一个变化的函数参数。
+
+ ```javascript
+ // really bad
+ function handleThings(opts) {
+ // 不!我们不应该改变函数参数。
+ // 更加糟糕: 如果参数 opts 是 false 的话,它就会被设定为一个对象。
+ // 但这样的写法会造成一些 Bugs。
+ //(译注:例如当 opts 被赋值为空字符串,opts 仍然会被下一行代码设定为一个空对象。)
+ opts = opts || {};
+ // ...
+ }
+
+ // still bad
+ function handleThings(opts) {
+ if (opts === void 0) {
+ opts = {};
+ }
+ // ...
+ }
+
+ // good
+ function handleThings(opts = {}) {
+ // ...
+ }
+ ```
+
+ - [7.8](#7.8) 直接给函数参数赋值时需要避免副作用。
+
+ > 为什么?因为这样的写法让人感到很困惑。
+
+ ```javascript
+ var b = 1;
+ // bad
+ function count(a = b++) {
+ console.log(a);
+ }
+ count(); // 1
+ count(); // 2
+ count(3); // 3
+ count(); // 3
+ ```
+
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 箭头函数
+
+ - [8.1](#8.1) 当你必须使用函数表达式(或传递一个匿名函数)时,使用箭头函数符号。
+
+ > 为什么?因为箭头函数创造了新的一个 `this` 执行环境(译注:参考 [Arrow functions - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) 和 [ES6 arrow functions, syntax and lexical scoping](http://toddmotto.com/es6-arrow-functions-syntaxes-and-lexical-scoping/)),通常情况下都能满足你的需求,而且这样的写法更为简洁。
+
+ > 为什么不?如果你有一个相当复杂的函数,你或许可以把逻辑部分转移到一个函数声明上。
+
+ ```javascript
+ // bad
+ [1, 2, 3].map(function (x) {
+ return x * x;
+ });
+
+ // good
+ [1, 2, 3].map((x) => {
+ return x * x;
+ });
+ ```
+
+ - [8.2](#8.2) 如果一个函数适合用一行写出并且只有一个参数,那就把花括号、圆括号和 `return` 都省略掉。如果不是,那就不要省略。
+
+ > 为什么?语法糖。在链式调用中可读性很高。
+
+ > 为什么不?当你打算回传一个对象的时候。
+
+ ```javascript
+ // good
+ [1, 2, 3].map(x => x * x);
+
+ // good
+ [1, 2, 3].reduce((total, n) => {
+ return total + n;
+ }, 0);
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 构造器
+
+ - [9.1](#9.1) 总是使用 `class`。避免直接操作 `prototype` 。
+
+ > 为什么? 因为 `class` 语法更为简洁更易读。
+
+ ```javascript
+ // bad
+ function Queue(contents = []) {
+ this._queue = [...contents];
+ }
+ Queue.prototype.pop = function() {
+ const value = this._queue[0];
+ this._queue.splice(0, 1);
+ return value;
+ }
+
+
+ // good
+ class Queue {
+ constructor(contents = []) {
+ this._queue = [...contents];
+ }
+ pop() {
+ const value = this._queue[0];
+ this._queue.splice(0, 1);
+ return value;
+ }
+ }
+ ```
+
+ - [9.2](#9.2) 使用 `extends` 继承。
+
+ > 为什么?因为 `extends` 是一个内建的原型继承方法并且不会破坏 `instanceof`。
+
+ ```javascript
+ // bad
+ const inherits = require('inherits');
+ function PeekableQueue(contents) {
+ Queue.apply(this, contents);
+ }
+ inherits(PeekableQueue, Queue);
+ PeekableQueue.prototype.peek = function() {
+ return this._queue[0];
+ }
+
+ // good
+ class PeekableQueue extends Queue {
+ peek() {
+ return this._queue[0];
+ }
+ }
+ ```
+
+ - [9.3](#9.3) 方法可以返回 `this` 来帮助链式调用。
+
+ ```javascript
+ // bad
+ Jedi.prototype.jump = function() {
+ this.jumping = true;
+ return true;
+ };
+
+ Jedi.prototype.setHeight = function(height) {
+ this.height = height;
+ };
+
+ const luke = new Jedi();
+ luke.jump(); // => true
+ luke.setHeight(20); // => undefined
+
+ // good
+ class Jedi {
+ jump() {
+ this.jumping = true;
+ return this;
+ }
+
+ setHeight(height) {
+ this.height = height;
+ return this;
+ }
+ }
+
+ const luke = new Jedi();
+
+ luke.jump()
+ .setHeight(20);
+ ```
+
+
+ - [9.4](#9.4) 可以写一个自定义的 `toString()` 方法,但要确保它能正常运行并且不会引起副作用。
+
+ ```javascript
+ class Jedi {
+ constructor(options = {}) {
+ this.name = options.name || 'no name';
+ }
+
+ getName() {
+ return this.name;
+ }
+
+ toString() {
+ return `Jedi - ${this.getName()}`;
+ }
+ }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 模块
+
+ - [10.1](#10.1) 总是使用模组 (`import`/`export`) 而不是其他非标准模块系统。你可以编译为你喜欢的模块系统。
+
+ > 为什么?模块就是未来,让我们开始迈向未来吧。
+
+ ```javascript
+ // bad
+ const AirbnbStyleGuide = require('./AirbnbStyleGuide');
+ module.exports = AirbnbStyleGuide.es6;
+
+ // ok
+ import AirbnbStyleGuide from './AirbnbStyleGuide';
+ export default AirbnbStyleGuide.es6;
+
+ // best
+ import { es6 } from './AirbnbStyleGuide';
+ export default es6;
+ ```
+
+ - [10.2](#10.2) 不要使用通配符 import。
+
+ > 为什么?这样能确保你只有一个默认 export。
+
+ ```javascript
+ // bad
+ import * as AirbnbStyleGuide from './AirbnbStyleGuide';
+
+ // good
+ import AirbnbStyleGuide from './AirbnbStyleGuide';
+ ```
+
+ - [10.3](#10.3) 不要从 import 中直接 export。
+
+ > 为什么?虽然一行代码简洁明了,但让 import 和 export 各司其职让事情能保持一致。
+
+ ```javascript
+ // bad
+ // filename es6.js
+ export { es6 as default } from './airbnbStyleGuide';
+
+ // good
+ // filename es6.js
+ import { es6 } from './AirbnbStyleGuide';
+ export default es6;
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## Iterators and Generators
+
+ - [11.1](#11.1) 不要使用 iterators。使用高阶函数例如 `map()` 和 `reduce()` 替代 `for-of`。
+
+ > 为什么?这加强了我们不变的规则。处理纯函数的回调值更易读,这比它带来的副作用更重要。
+
+ ```javascript
+ const numbers = [1, 2, 3, 4, 5];
+
+ // bad
+ let sum = 0;
+ for (let num of numbers) {
+ sum += num;
+ }
+
+ sum === 15;
+
+ // good
+ let sum = 0;
+ numbers.forEach((num) => sum += num);
+ sum === 15;
+
+ // best (use the functional force)
+ const sum = numbers.reduce((total, num) => total + num, 0);
+ sum === 15;
+ ```
+
+ - [11.2](#11.2) 现在还不要使用 generators。
+
+ > 为什么?因为它们现在还没法很好地编译到 ES5。 (译者注:目前(2016/03) Chrome 和 Node.js 的稳定版本都已支持 generators)
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 属性
+
+ - [12.1](#12.1) 使用 `.` 来访问对象的属性。
+
+ ```javascript
+ const luke = {
+ jedi: true,
+ age: 28,
+ };
+
+ // bad
+ const isJedi = luke['jedi'];
+
+ // good
+ const isJedi = luke.jedi;
+ ```
+
+ - [12.2](#12.2) 当通过变量访问属性时使用中括号 `[]`。
+
+ ```javascript
+ const luke = {
+ jedi: true,
+ age: 28,
+ };
+
+ function getProp(prop) {
+ return luke[prop];
+ }
+
+ const isJedi = getProp('jedi');
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 变量
+
+ - [13.1](#13.1) 一直使用 `const` 来声明变量,如果不这样做就会产生全局变量。我们需要避免全局命名空间的污染。[地球队长](http://www.wikiwand.com/en/Captain_Planet)已经警告过我们了。(译注:全局,global 亦有全球的意思。地球队长的责任是保卫地球环境,所以他警告我们不要造成「全球」污染。)
+
+ ```javascript
+ // bad
+ superPower = new SuperPower();
+
+ // good
+ const superPower = new SuperPower();
+ ```
+
+ - [13.2](#13.2) 使用 `const` 声明每一个变量。
+
+ > 为什么?增加新变量将变的更加容易,而且你永远不用再担心调换错 `;` 跟 `,`。
+
+ ```javascript
+ // bad
+ const items = getItems(),
+ goSportsTeam = true,
+ dragonball = 'z';
+
+ // bad
+ // (compare to above, and try to spot the mistake)
+ const items = getItems(),
+ goSportsTeam = true;
+ dragonball = 'z';
+
+ // good
+ const items = getItems();
+ const goSportsTeam = true;
+ const dragonball = 'z';
+ ```
+
+ - [13.3](#13.3) 将所有的 `const` 和 `let` 分组
+
+ > 为什么?当你需要把已赋值变量赋值给未赋值变量时非常有用。
+
+ ```javascript
+ // bad
+ let i, len, dragonball,
+ items = getItems(),
+ goSportsTeam = true;
+
+ // bad
+ let i;
+ const items = getItems();
+ let dragonball;
+ const goSportsTeam = true;
+ let len;
+
+ // good
+ const goSportsTeam = true;
+ const items = getItems();
+ let dragonball;
+ let i;
+ let length;
+ ```
+
+ - [13.4](#13.4) 在你需要的地方给变量赋值,但请把它们放在一个合理的位置。
+
+ > 为什么?`let` 和 `const` 是块级作用域而不是函数作用域。
+
+ ```javascript
+ // good
+ function() {
+ test();
+ console.log('doing stuff..');
+
+ //..other stuff..
+
+ const name = getName();
+
+ if (name === 'test') {
+ return false;
+ }
+
+ return name;
+ }
+
+ // bad - unnecessary function call
+ function(hasName) {
+ const name = getName();
+
+ if (!hasName) {
+ return false;
+ }
+
+ this.setFirstName(name);
+
+ return true;
+ }
+
+ // good
+ function(hasName) {
+ if (!hasName) {
+ return false;
+ }
+
+ const name = getName();
+ this.setFirstName(name);
+
+ return true;
+ }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## Hoisting
+
+ - [14.1](#14.1) `var` 声明会被提升至该作用域的顶部,但它们赋值不会提升。`let` 和 `const` 被赋予了一种称为「[暂时性死区(Temporal Dead Zones, TDZ)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let)」的概念。这对于了解为什么 [type of 不再安全](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15)相当重要。
+
+ ```javascript
+ // 我们知道这样运行不了
+ // (假设 notDefined 不是全局变量)
+ function example() {
+ console.log(notDefined); // => throws a ReferenceError
+ }
+
+ // 由于变量提升的原因,
+ // 在引用变量后再声明变量是可以运行的。
+ // 注:变量的赋值 `true` 不会被提升。
+ function example() {
+ console.log(declaredButNotAssigned); // => undefined
+ var declaredButNotAssigned = true;
+ }
+
+ // 编译器会把函数声明提升到作用域的顶层,
+ // 这意味着我们的例子可以改写成这样:
+ function example() {
+ let declaredButNotAssigned;
+ console.log(declaredButNotAssigned); // => undefined
+ declaredButNotAssigned = true;
+ }
+
+ // 使用 const 和 let
+ function example() {
+ console.log(declaredButNotAssigned); // => throws a ReferenceError
+ console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
+ const declaredButNotAssigned = true;
+ }
+ ```
+
+ - [14.2](#14.2) 匿名函数表达式的变量名会被提升,但函数内容并不会。
+
+ ```javascript
+ function example() {
+ console.log(anonymous); // => undefined
+
+ anonymous(); // => TypeError anonymous is not a function
+
+ var anonymous = function() {
+ console.log('anonymous function expression');
+ };
+ }
+ ```
+
+ - [14.3](#14.3) 命名的函数表达式的变量名会被提升,但函数名和函数函数内容并不会。
+
+ ```javascript
+ function example() {
+ console.log(named); // => undefined
+
+ named(); // => TypeError named is not a function
+
+ superPower(); // => ReferenceError superPower is not defined
+
+ var named = function superPower() {
+ console.log('Flying');
+ };
+ }
+
+ // the same is true when the function name
+ // is the same as the variable name.
+ function example() {
+ console.log(named); // => undefined
+
+ named(); // => TypeError named is not a function
+
+ var named = function named() {
+ console.log('named');
+ }
+ }
+ ```
+
+ - [14.4](#14.4) 函数声明的名称和函数体都会被提升。
+
+ ```javascript
+ function example() {
+ superPower(); // => Flying
+
+ function superPower() {
+ console.log('Flying');
+ }
+ }
+ ```
+
+ - 想了解更多信息,参考 [Ben Cherry](http://www.adequatelygood.com/) 的 [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting)。
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 比较运算符 & 等号
+
+ - [15.1](#15.1) 优先使用 `===` 和 `!==` 而不是 `==` 和 `!=`.
+ - [15.2](#15.2) 条件表达式例如 `if` 语句通过抽象方法 `ToBoolean` 强制计算它们的表达式并且总是遵守下面的规则:
+
+ + **对象** 被计算为 **true**
+ + **Undefined** 被计算为 **false**
+ + **Null** 被计算为 **false**
+ + **布尔值** 被计算为 **布尔的值**
+ + **数字** 如果是 **+0、-0、或 NaN** 被计算为 **false**, 否则为 **true**
+ + **字符串** 如果是空字符串 `''` 被计算为 **false**,否则为 **true**
+
+ ```javascript
+ if ([0]) {
+ // true
+ // An array is an object, objects evaluate to true
+ }
+ ```
+
+ - [15.3](#15.3) 使用简写。
+
+ ```javascript
+ // bad
+ if (name !== '') {
+ // ...stuff...
+ }
+
+ // good
+ if (name) {
+ // ...stuff...
+ }
+
+ // bad
+ if (collection.length > 0) {
+ // ...stuff...
+ }
+
+ // good
+ if (collection.length) {
+ // ...stuff...
+ }
+ ```
+
+ - [15.4](#15.4) 想了解更多信息,参考 Angus Croll 的 [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108)。
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 代码块
+
+ - [16.1](#16.1) 使用大括号包裹所有的多行代码块。
+
+ ```javascript
+ // bad
+ if (test)
+ return false;
+
+ // good
+ if (test) return false;
+
+ // good
+ if (test) {
+ return false;
+ }
+
+ // bad
+ function() { return false; }
+
+ // good
+ function() {
+ return false;
+ }
+ ```
+
+ - [16.2](#16.2) 如果通过 `if` 和 `else` 使用多行代码块,把 `else` 放在 `if` 代码块关闭括号的同一行。
+
+ ```javascript
+ // bad
+ if (test) {
+ thing1();
+ thing2();
+ }
+ else {
+ thing3();
+ }
+
+ // good
+ if (test) {
+ thing1();
+ thing2();
+ } else {
+ thing3();
+ }
+ ```
+
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 注释
+
+ - [17.1](#17.1) 使用 `/** ... */` 作为多行注释。包含描述、指定所有参数和返回值的类型和值。
+
+ ```javascript
+ // bad
+ // make() returns a new element
+ // based on the passed in tag name
+ //
+ // @param {String} tag
+ // @return {Element} element
+ function make(tag) {
+
+ // ...stuff...
+
+ return element;
+ }
+
+ // good
+ /**
+ * make() returns a new element
+ * based on the passed in tag name
+ *
+ * @param {String} tag
+ * @return {Element} element
+ */
+ function make(tag) {
+
+ // ...stuff...
+
+ return element;
+ }
+ ```
+
+ - [17.2](#17.2) 使用 `//` 作为单行注释。在评论对象上面另起一行使用单行注释。在注释前插入空行。
+
+ ```javascript
+ // bad
+ const active = true; // is current tab
+
+ // good
+ // is current tab
+ const active = true;
+
+ // bad
+ function getType() {
+ console.log('fetching type...');
+ // set the default type to 'no type'
+ const type = this._type || 'no type';
+
+ return type;
+ }
+
+ // good
+ function getType() {
+ console.log('fetching type...');
+
+ // set the default type to 'no type'
+ const type = this._type || 'no type';
+
+ return type;
+ }
+ ```
+
+ - [17.3](#17.3) 给注释增加 `FIXME` 或 `TODO` 的前缀可以帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。这将有别于常见的注释,因为它们是可操作的。使用 `FIXME -- need to figure this out` 或者 `TODO -- need to implement`。
+
+ - [17.4](#17.4) 使用 `// FIXME`: 标注问题。
+
+ ```javascript
+ class Calculator {
+ constructor() {
+ // FIXME: shouldn't use a global here
+ total = 0;
+ }
+ }
+ ```
+
+ - [17.5](#17.5) 使用 `// TODO`: 标注问题的解决方式。
+
+ ```javascript
+ class Calculator {
+ constructor() {
+ // TODO: total should be configurable by an options param
+ this.total = 0;
+ }
+ }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 空白
+
+ - [18.1](#18.1) 使用 2 个空格作为缩进。
+
+ ```javascript
+ // bad
+ function() {
+ ∙∙∙∙const name;
+ }
+
+ // bad
+ function() {
+ ∙const name;
+ }
+
+ // good
+ function() {
+ ∙∙const name;
+ }
+ ```
+
+ - [18.2](#18.2) 在花括号前放一个空格。
+
+ ```javascript
+ // bad
+ function test(){
+ console.log('test');
+ }
+
+ // good
+ function test() {
+ console.log('test');
+ }
+
+ // bad
+ dog.set('attr',{
+ age: '1 year',
+ breed: 'Bernese Mountain Dog',
+ });
+
+ // good
+ dog.set('attr', {
+ age: '1 year',
+ breed: 'Bernese Mountain Dog',
+ });
+ ```
+
+ - [18.3](#18.3) 在控制语句(`if`、`while` 等)的小括号前放一个空格。在函数调用及声明中,不在函数的参数列表前加空格。
+
+ ```javascript
+ // bad
+ if(isJedi) {
+ fight ();
+ }
+
+ // good
+ if (isJedi) {
+ fight();
+ }
+
+ // bad
+ function fight () {
+ console.log ('Swooosh!');
+ }
+
+ // good
+ function fight() {
+ console.log('Swooosh!');
+ }
+ ```
+
+ - [18.4](#18.4) 使用空格把运算符隔开。
+
+ ```javascript
+ // bad
+ const x=y+5;
+
+ // good
+ const x = y + 5;
+ ```
+
+ - [18.5](#18.5) 在文件末尾插入一个空行。
+
+ ```javascript
+ // bad
+ (function(global) {
+ // ...stuff...
+ })(this);
+ ```
+
+ ```javascript
+ // bad
+ (function(global) {
+ // ...stuff...
+ })(this);↵
+ ↵
+ ```
+
+ ```javascript
+ // good
+ (function(global) {
+ // ...stuff...
+ })(this);↵
+ ```
+
+ - [18.5](#18.5) 在使用长方法链时进行缩进。使用前面的点 `.` 强调这是方法调用而不是新语句。
+
+ ```javascript
+ // bad
+ $('#items').find('.selected').highlight().end().find('.open').updateCount();
+
+ // bad
+ $('#items').
+ find('.selected').
+ highlight().
+ end().
+ find('.open').
+ updateCount();
+
+ // good
+ $('#items')
+ .find('.selected')
+ .highlight()
+ .end()
+ .find('.open')
+ .updateCount();
+
+ // bad
+ const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
+ .attr('width', (radius + margin) * 2).append('svg:g')
+ .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
+ .call(tron.led);
+
+ // good
+ const leds = stage.selectAll('.led')
+ .data(data)
+ .enter().append('svg:svg')
+ .classed('led', true)
+ .attr('width', (radius + margin) * 2)
+ .append('svg:g')
+ .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
+ .call(tron.led);
+ ```
+
+ - [18.6](#18.6) 在块末和新语句前插入空行。
+
+ ```javascript
+ // bad
+ if (foo) {
+ return bar;
+ }
+ return baz;
+
+ // good
+ if (foo) {
+ return bar;
+ }
+
+ return baz;
+
+ // bad
+ const obj = {
+ foo() {
+ },
+ bar() {
+ },
+ };
+ return obj;
+
+ // good
+ const obj = {
+ foo() {
+ },
+
+ bar() {
+ },
+ };
+
+ return obj;
+ ```
+
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 逗号
+
+ - [19.1](#19.1) 行首逗号:**不需要**。
+
+ ```javascript
+ // bad
+ const story = [
+ once
+ , upon
+ , aTime
+ ];
+
+ // good
+ const story = [
+ once,
+ upon,
+ aTime,
+ ];
+
+ // bad
+ const hero = {
+ firstName: 'Ada'
+ , lastName: 'Lovelace'
+ , birthYear: 1815
+ , superPower: 'computers'
+ };
+
+ // good
+ const hero = {
+ firstName: 'Ada',
+ lastName: 'Lovelace',
+ birthYear: 1815,
+ superPower: 'computers',
+ };
+ ```
+
+ - [19.2](#19.2) 增加结尾的逗号: **需要**。
+
+ > 为什么? 这会让 git diffs 更干净。另外,像 babel 这样的转译器会移除结尾多余的逗号,也就是说你不必担心老旧浏览器的[尾逗号问题](es5/README.md#commas)。
+
+ ```javascript
+ // bad - git diff without trailing comma
+ const hero = {
+ firstName: 'Florence',
+ - lastName: 'Nightingale'
+ + lastName: 'Nightingale',
+ + inventorOf: ['coxcomb graph', 'modern nursing']
+ }
+
+ // good - git diff with trailing comma
+ const hero = {
+ firstName: 'Florence',
+ lastName: 'Nightingale',
+ + inventorOf: ['coxcomb chart', 'modern nursing'],
+ }
+
+ // bad
+ const hero = {
+ firstName: 'Dana',
+ lastName: 'Scully'
+ };
+
+ const heroes = [
+ 'Batman',
+ 'Superman'
+ ];
+
+ // good
+ const hero = {
+ firstName: 'Dana',
+ lastName: 'Scully',
+ };
+
+ const heroes = [
+ 'Batman',
+ 'Superman',
+ ];
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 分号
+
+ - [20.1](#20.1) **使用分号**
+
+ ```javascript
+ // bad
+ (function() {
+ const name = 'Skywalker'
+ return name
+ })()
+
+ // good
+ (() => {
+ const name = 'Skywalker';
+ return name;
+ })();
+
+ // good (防止函数在两个 IIFE 合并时被当成一个参数)
+ ;(() => {
+ const name = 'Skywalker';
+ return name;
+ })();
+ ```
+
+ [Read more](http://stackoverflow.com/a/7365214/1712802).
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 类型转换
+
+ - [21.1](#21.1) 在语句开始时执行类型转换。
+ - [21.2](#21.2) 字符串:
+
+ ```javascript
+ // => this.reviewScore = 9;
+
+ // bad
+ const totalScore = this.reviewScore + '';
+
+ // good
+ const totalScore = String(this.reviewScore);
+ ```
+
+ - [21.3](#21.3) 对数字使用 `parseInt` 转换,并带上类型转换的基数。
+
+ ```javascript
+ const inputValue = '4';
+
+ // bad
+ const val = new Number(inputValue);
+
+ // bad
+ const val = +inputValue;
+
+ // bad
+ const val = inputValue >> 0;
+
+ // bad
+ const val = parseInt(inputValue);
+
+ // good
+ const val = Number(inputValue);
+
+ // good
+ const val = parseInt(inputValue, 10);
+ ```
+
+ - [21.4](#21.4) 如果因为某些原因 parseInt 成为你所做的事的瓶颈而需要使用位操作解决[性能问题](http://jsperf.com/coercion-vs-casting/3)时,留个注释说清楚原因和你的目的。
+
+ ```javascript
+ // good
+ /**
+ * 使用 parseInt 导致我的程序变慢,
+ * 改成使用位操作转换数字快多了。
+ */
+ const val = inputValue >> 0;
+ ```
+
+ - [21.5](#21.5) **注:** 小心使用位操作运算符。数字会被当成 [64 位值](http://es5.github.io/#x4.3.19),但是位操作运算符总是返回 32 位的整数([参考](http://es5.github.io/#x11.7))。位操作处理大于 32 位的整数值时还会导致意料之外的行为。[关于这个问题的讨论](https://github.com/airbnb/javascript/issues/109)。最大的 32 位整数是 2,147,483,647:
+
+ ```javascript
+ 2147483647 >> 0 //=> 2147483647
+ 2147483648 >> 0 //=> -2147483648
+ 2147483649 >> 0 //=> -2147483647
+ ```
+
+ - [21.6](#21.6) 布尔:
+
+ ```javascript
+ const age = 0;
+
+ // bad
+ const hasAge = new Boolean(age);
+
+ // good
+ const hasAge = Boolean(age);
+
+ // good
+ const hasAge = !!age;
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 命名规则
+
+ - [22.1](#22.1) 避免单字母命名。命名应具备描述性。
+
+ ```javascript
+ // bad
+ function q() {
+ // ...stuff...
+ }
+
+ // good
+ function query() {
+ // ..stuff..
+ }
+ ```
+
+ - [22.2](#22.2) 使用驼峰式命名对象、函数和实例。
+
+ ```javascript
+ // bad
+ const OBJEcttsssss = {};
+ const this_is_my_object = {};
+ function c() {}
+
+ // good
+ const thisIsMyObject = {};
+ function thisIsMyFunction() {}
+ ```
+
+ - [22.3](#22.3) 使用帕斯卡式命名构造函数或类。
+
+ ```javascript
+ // bad
+ function user(options) {
+ this.name = options.name;
+ }
+
+ const bad = new user({
+ name: 'nope',
+ });
+
+ // good
+ class User {
+ constructor(options) {
+ this.name = options.name;
+ }
+ }
+
+ const good = new User({
+ name: 'yup',
+ });
+ ```
+
+ - [22.4](#22.4) 使用下划线 `_` 开头命名私有属性。
+
+ ```javascript
+ // bad
+ this.__firstName__ = 'Panda';
+ this.firstName_ = 'Panda';
+
+ // good
+ this._firstName = 'Panda';
+ ```
+
+ - [22.5](#22.5) 别保存 `this` 的引用。使用箭头函数或 Function#bind。
+
+ ```javascript
+ // bad
+ function foo() {
+ const self = this;
+ return function() {
+ console.log(self);
+ };
+ }
+
+ // bad
+ function foo() {
+ const that = this;
+ return function() {
+ console.log(that);
+ };
+ }
+
+ // good
+ function foo() {
+ return () => {
+ console.log(this);
+ };
+ }
+ ```
+
+ - [22.6](#22.6) 如果你的文件只输出一个类,那你的文件名必须和类名完全保持一致。
+
+ ```javascript
+ // file contents
+ class CheckBox {
+ // ...
+ }
+ export default CheckBox;
+
+ // in some other file
+ // bad
+ import CheckBox from './checkBox';
+
+ // bad
+ import CheckBox from './check_box';
+
+ // good
+ import CheckBox from './CheckBox';
+ ```
+
+ - [22.7](#22.7) 当你导出默认的函数时使用驼峰式命名。你的文件名必须和函数名完全保持一致。
+
+ ```javascript
+ function makeStyleGuide() {
+ }
+
+ export default makeStyleGuide;
+ ```
+
+ - [22.8](#22.8) 当你导出单例、函数库、空对象时使用帕斯卡式命名。
+
+ ```javascript
+ const AirbnbStyleGuide = {
+ es6: {
+ }
+ };
+
+ export default AirbnbStyleGuide;
+ ```
+
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 存取器
+
+ - [23.1](#23.1) 属性的存取函数不是必须的。
+ - [23.2](#23.2) 如果你需要存取函数时使用 `getVal()` 和 `setVal('hello')`。
+
+ ```javascript
+ // bad
+ dragon.age();
+
+ // good
+ dragon.getAge();
+
+ // bad
+ dragon.age(25);
+
+ // good
+ dragon.setAge(25);
+ ```
+
+ - [23.3](#23.3) 如果属性是布尔值,使用 `isVal()` 或 `hasVal()`。
+
+ ```javascript
+ // bad
+ if (!dragon.age()) {
+ return false;
+ }
+
+ // good
+ if (!dragon.hasAge()) {
+ return false;
+ }
+ ```
+
+ - [23.4](#23.4) 创建 `get()` 和 `set()` 函数是可以的,但要保持一致。
+
+ ```javascript
+ class Jedi {
+ constructor(options = {}) {
+ const lightsaber = options.lightsaber || 'blue';
+ this.set('lightsaber', lightsaber);
+ }
+
+ set(key, val) {
+ this[key] = val;
+ }
+
+ get(key) {
+ return this[key];
+ }
+ }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 事件
+
+ - [24.1](#24.1) 当给事件附加数据时(无论是 DOM 事件还是私有事件),传入一个哈希而不是原始值。这样可以让后面的贡献者增加更多数据到事件数据而无需找出并更新事件的每一个处理器。例如,不好的写法:
+
+ ```javascript
+ // bad
+ $(this).trigger('listingUpdated', listing.id);
+
+ ...
+
+ $(this).on('listingUpdated', function(e, listingId) {
+ // do something with listingId
+ });
+ ```
+
+ 更好的写法:
+
+ ```javascript
+ // good
+ $(this).trigger('listingUpdated', { listingId : listing.id });
+
+ ...
+
+ $(this).on('listingUpdated', function(e, data) {
+ // do something with data.listingId
+ });
+ ```
+
+ **[⬆ 返回目录](#table-of-contents)**
+
+
+## jQuery
+
+ - [25.1](#25.1) 使用 `$` 作为存储 jQuery 对象的变量名前缀。
+
+ ```javascript
+ // bad
+ const sidebar = $('.sidebar');
+
+ // good
+ const $sidebar = $('.sidebar');
+ ```
+
+ - [25.2](#25.2) 缓存 jQuery 查询。
+
+ ```javascript
+ // bad
+ function setSidebar() {
+ $('.sidebar').hide();
+
+ // ...stuff...
+
+ $('.sidebar').css({
+ 'background-color': 'pink'
+ });
+ }
+
+ // good
+ function setSidebar() {
+ const $sidebar = $('.sidebar');
+ $sidebar.hide();
+
+ // ...stuff...
+
+ $sidebar.css({
+ 'background-color': 'pink'
+ });
+ }
+ ```
+
+ - [25.3](#25.3) 对 DOM 查询使用层叠 `$('.sidebar ul')` 或 父元素 > 子元素 `$('.sidebar > ul')`。 [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)
+ - [25.4](#25.4) 对有作用域的 jQuery 对象查询使用 `find`。
+
+ ```javascript
+ // bad
+ $('ul', '.sidebar').hide();
+
+ // bad
+ $('.sidebar').find('ul').hide();
+
+ // good
+ $('.sidebar ul').hide();
+
+ // good
+ $('.sidebar > ul').hide();
+
+ // good
+ $sidebar.find('ul').hide();
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## ECMAScript 5 兼容性
+
+ - [26.1](#26.1) 参考 [Kangax](https://twitter.com/kangax/) 的 ES5 [兼容性](http://kangax.github.com/es5-compat-table/).
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## ECMAScript 6 规范
+
+ - [27.1](#27.1) 以下是链接到 ES6 的各个特性的列表。
+
+1. [Arrow Functions](#arrow-functions)
+1. [Classes](#constructors)
+1. [Object Shorthand](#es6-object-shorthand)
+1. [Object Concise](#es6-object-concise)
+1. [Object Computed Properties](#es6-computed-properties)
+1. [Template Strings](#es6-template-literals)
+1. [Destructuring](#destructuring)
+1. [Default Parameters](#es6-default-parameters)
+1. [Rest](#es6-rest)
+1. [Array Spreads](#es6-array-spreads)
+1. [Let and Const](#references)
+1. [Iterators and Generators](#iterators-and-generators)
+1. [Modules](#modules)
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 测试
+
+ - [28.1](#28.1) **Yup.**
+
+ ```javascript
+ function() {
+ return true;
+ }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 性能
+
+ - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/)
+ - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2)
+ - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost)
+ - [Bang Function](http://jsperf.com/bang-function)
+ - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13)
+ - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text)
+ - [Long String Concatenation](http://jsperf.com/ya-string-concat)
+ - Loading...
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 资源
+
+**Learning ES6**
+
+ - [Draft ECMA 2015 (ES6) Spec](https://people.mozilla.org/~jorendorff/es6-draft.html)
+ - [ExploringJS](http://exploringjs.com/)
+ - [ES6 Compatibility Table](https://kangax.github.io/compat-table/es6/)
+ - [Comprehensive Overview of ES6 Features](http://es6-features.org/)
+
+**Read This**
+
+ - [Annotated ECMAScript 5.1](http://es5.github.com/)
+
+**Tools**
+
+ - Code Style Linters
+ + [ESlint](http://eslint.org/) - [Airbnb Style .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc)
+ + [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/jshintrc)
+ + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json)
+
+**Other Styleguides**
+
+ - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml)
+ - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines)
+ - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/)
+
+**Other Styles**
+
+ - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen
+ - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen
+ - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun
+ - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman
+
+**Further Reading**
+
+ - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll
+ - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer
+ - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz
+ - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban
+ - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock
+
+**Books**
+
+ - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford
+ - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov
+ - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz
+ - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders
+ - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas
+ - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw
+ - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig
+ - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch
+ - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault
+ - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg
+ - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
+ - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon
+ - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov
+ - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman
+ - [Eloquent JavaScript](http://eloquentjavascript.net/) - Marijn Haverbeke
+
+**Blogs**
+
+ - [DailyJS](http://dailyjs.com/)
+ - [JavaScript Weekly](http://javascriptweekly.com/)
+ - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/)
+ - [Bocoup Weblog](http://weblog.bocoup.com/)
+ - [Adequately Good](http://www.adequatelygood.com/)
+ - [NCZOnline](http://www.nczonline.net/)
+ - [Perfection Kills](http://perfectionkills.com/)
+ - [Ben Alman](http://benalman.com/)
+ - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/)
+ - [Dustin Diaz](http://dustindiaz.com/)
+ - [nettuts](http://net.tutsplus.com/?s=javascript)
+
+**Podcasts**
+
+ - [JavaScript Jabber](http://devchat.tv/js-jabber/)
+
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 使用人群
+
+ This is a list of organizations that are using this style guide. Send us a pull request or open an issue and we'll add you to the list.
+
+ - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript)
+ - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript)
+ - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript)
+ - **American Insitutes for Research**: [AIRAST/javascript](https://github.com/AIRAST/javascript)
+ - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript)
+ - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript)
+ - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript)
+ - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide)
+ - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript)
+ - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript)
+ - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide)
+ - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript)
+ - **Expensify** [Expensify/Style-Guide](https://github.com/Expensify/Style-Guide/blob/master/javascript.md)
+ - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide)
+ - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript)
+ - **GeneralElectric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript)
+ - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style)
+ - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript)
+ - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript)
+ - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide)
+ - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript)
+ - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions)
+ - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript)
+ - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/javascript)
+ - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript)
+ - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript)
+ - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript)
+ - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript)
+ - **Muber**: [muber/javascript](https://github.com/muber/javascript)
+ - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript)
+ - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript)
+ - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript)
+ - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript)
+ - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript)
+ - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide)
+ - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript)
+ - **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide)
+ - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide)
+ - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide)
+ - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript)
+ - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/javascript)
+ - **Target**: [target/javascript](https://github.com/target/javascript)
+ - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript)
+ - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript)
+ - **Userify**: [userify/javascript](https://github.com/userify/javascript)
+ - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide)
+ - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript)
+ - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript)
+ - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript)
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 翻译
+
+ This style guide is also available in other languages:
+
+ -  **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide)
+ -  **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript)
+ -  **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide)
+ -  **Chinese(Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript)
+ -  **Chinese(Simplified)**: [yuche/javascript](https://github.com/yuche/javascript)
+ -  **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide)
+ -  **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide)
+ -  **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide)
+ -  **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide)
+ -  **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide)
+ -  **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript)
+ -  **Russian**: [uprock/javascript](https://github.com/uprock/javascript)
+ -  **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide)
+ -  **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide)
+
+
+## JavaScript 编码规范说明
+
+ - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide)
+
+
+## 一起来讨论 JavaScript
+
+ - Find us on [gitter](https://gitter.im/airbnb/javascript).
+
+## Contributors
+
+ - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors)
+
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2014 Airbnb
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**[⬆ 返回目录](#table-of-contents)**
+
+# };
diff --git a/docs/es6_zh-cn_v2.md b/docs/es6_zh-cn_v2.md
new file mode 100644
index 0000000000..63be40ff86
--- /dev/null
+++ b/docs/es6_zh-cn_v2.md
@@ -0,0 +1,3303 @@
+[](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+# Airbnb JavaScript Style Guide() {
+
+**A mostly reasonable approach to JavaScript——用更合理的方式写 JavaScript**
+
+翻译自 [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) 。
+
+ES5 的编码规范请查看[版本一](https://github.com/webcoding/javascript-style-guide/tree/master/docs/es5_zh-cn_v1.md),[版本二](https://github.com/webcoding/javascript-style-guide/tree/master/docs/es5_zh-cn_v2.md)。
+
+[](https://www.npmjs.com/package/eslint-config-airbnb)
+[](https://www.npmjs.com/package/eslint-config-airbnb-base)
+[](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+Other Style Guides
+ - [ES5 (Deprecated)](https://github.com/airbnb/javascript/tree/es5-deprecated/es5)
+ - [React](react/)
+ - [CSS-in-JavaScript](css-in-javascript/)
+ - [CSS & Sass](https://github.com/airbnb/css)
+ - [CSS & Sass 中文版](https://github.com/webcoding/css-style-guide)
+ - [Ruby](https://github.com/airbnb/ruby)
+
+
+## 目录
+
+ 1. [类型](#types)
+ 1. [引用](#references)
+ 1. [对象](#objects)
+ 1. [数组](#arrays)
+ 1. [解构](#destructuring)
+ 1. [字符串](#strings)
+ 1. [函数](#functions)
+ 1. [箭头函数](#arrow-functions)
+ 1. [类 & 构造函数](#classes--constructors)
+ 1. [模块](#modules)
+ 1. [Iterators & Generators ](#iterators-and-generators)
+ 1. [属性](#properties)
+ 1. [变量](#variables)
+ 1. [提升](#hoisting)
+ 1. [比较运算符 & 等号](#comparison-operators--equality)
+ 1. [代码块](#blocks)
+ 1. [注释](#comments)
+ 1. [空白](#whitespace)
+ 1. [逗号](#commas)
+ 1. [分号](#semicolons)
+ 1. [类型转换](#type-casting--coercion)
+ 1. [命名规则](#naming-conventions)
+ 1. [存取器](#accessors)
+ 1. [事件](#events)
+ 1. [jQuery](#jquery)
+ 1. [ECMAScript 5 兼容性](#ecmascript-5-compatibility)
+ 1. [ECMAScript 6 (ES 2015+) 编码规范](#ecmascript-6-styles)
+ 1. [测试](#testing)
+ 1. [性能](#performance)
+ 1. [资源](#resources)
+ 1. [使用人群](#in-the-wild)
+ 1. [翻译](#translation)
+ 1. [JavaScript 编码规范说明](#the-javascript-style-guide-guide)
+ 1. [一起来讨论 JavaScript](#chat-with-us-about-javascript)
+ 1. [Contributors](#contributors)
+ 1. [License](#license)
+
+
+## 类型
+
+
+ - [1.1](#types--primitives) **基本类型**: 直接存取基本类型。
+
+ + `string` 字符串
+ + `number` 数值
+ + `boolean` 布尔类型
+ + `null`
+ + `undefined`
+
+ ```javascript
+ const foo = 1;
+ let bar = foo;
+
+ bar = 9;
+
+ console.log(foo, bar); // => 1, 9
+ ```
+
+
+ - [1.2](#types--complex) **复杂类型**: 通过引用的方式存取复杂类型。
+
+ + `object` 对象
+ + `array` 数组
+ + `function` 函数
+
+ ```javascript
+ const foo = [1, 2];
+ const bar = foo;
+
+ bar[0] = 9;
+
+ console.log(foo[0], bar[0]); // => 9, 9
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 引用
+
+
+ - [2.1](#references--prefer-const) 对所有的引用使用 `const` ;不要使用 `var`。
+ eslint: [`prefer-const`](http://eslint.org/docs/rules/prefer-const.html), [`no-const-assign`](http://eslint.org/docs/rules/no-const-assign.html)
+
+ > 为什么? 这能确保你无法对引用重新赋值,也不会导致出现 bug 或难以理解。
+
+ ```javascript
+ // bad
+ var a = 1;
+ var b = 2;
+
+ // good
+ const a = 1;
+ const b = 2;
+ ```
+
+
+ - [2.2](#references--disallow-var) 如果你一定需要可变动的引用,使用 `let` 代替 `var`。
+ eslint: [`no-var`](http://eslint.org/docs/rules/no-var.html)
+ jscs: [`disallowVar`](http://jscs.info/rule/disallowVar)
+
+ > 为什么? 因为 `let` 是块级作用域,而 `var` 是函数作用域。
+
+ ```javascript
+ // bad
+ var count = 1;
+ if (true) {
+ count += 1;
+ }
+
+ // good, use the let.
+ let count = 1;
+ if (true) {
+ count += 1;
+ }
+ ```
+
+
+ - [2.3](#references--block-scope) 注意 `let` 和 `const` 都是块级作用域。
+
+ ```javascript
+ // const 和 let 只存在于它们被定义的区块内。
+ {
+ let a = 1;
+ const b = 1;
+ }
+ console.log(a); // ReferenceError
+ console.log(b); // ReferenceError
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 对象
+
+
+ - [3.1](#objects--no-new) 使用字面值创建对象。
+ eslint: [`no-new-object`](http://eslint.org/docs/rules/no-new-object.html)
+
+ ```javascript
+ // bad
+ const item = new Object();
+
+ // good
+ const item = {};
+ ```
+ ****************
+ - [3.2](#3.2) 如果你的代码在浏览器环境下执行,别使用 [保留字](http://es5.github.io/#x7.6.1) 作为键值。这样的话在 IE8 不会运行。 [更多信息](https://github.com/airbnb/javascript/issues/61)。 但在 ES6 模块和服务器端中使用没有问题。
+
+ ```javascript
+ // bad
+ const superman = {
+ default: { clark: 'kent' },
+ private: true,
+ };
+
+ // good
+ const superman = {
+ defaults: { clark: 'kent' },
+ hidden: true,
+ };
+ ```
+
+ - [3.3](#3.3) 使用同义词替换需要使用的保留字。
+
+ ```javascript
+ // bad
+ const superman = {
+ class: 'alien',
+ };
+
+ // bad
+ const superman = {
+ klass: 'alien',
+ };
+
+ // good
+ const superman = {
+ type: 'alien',
+ };
+ ```
+ *************
+
+
+ - [3.2](#es6-computed-properties) 创建有动态属性名的对象时,使用可被计算的属性名称。
+
+ > 为什么? 因为这样可以让你在一个地方定义所有的对象属性。
+
+ ```javascript
+ function getKey(k) {
+ return `a key named ${k}`;
+ }
+
+ // bad
+ const obj = {
+ id: 5,
+ name: 'San Francisco',
+ };
+ obj[getKey('enabled')] = true;
+
+ // good
+ const obj = {
+ id: 5,
+ name: 'San Francisco',
+ [getKey('enabled')]: true,
+ };
+ ```
+
+
+ - [3.3](#es6-object-shorthand) 使用对象方法的简写。
+ eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html)
+ jscs: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals)
+
+ ```javascript
+ // bad
+ const atom = {
+ value: 1,
+
+ addValue: function (value) {
+ return atom.value + value;
+ },
+ };
+
+ // good
+ const atom = {
+ value: 1,
+
+ addValue(value) {
+ return atom.value + value;
+ },
+ };
+ ```
+
+
+ - [3.4](#es6-object-concise) 使用对象属性值的简写。
+ eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html)
+ jscs: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals)
+
+ > 为什么? 因为这样更短更有描述性。
+
+ ```javascript
+ const lukeSkywalker = 'Luke Skywalker';
+
+ // bad
+ const obj = {
+ lukeSkywalker: lukeSkywalker,
+ };
+
+ // good
+ const obj = {
+ lukeSkywalker,
+ };
+ ```
+
+
+ - [3.5](#objects--grouped-shorthand) 在对象属性声明前把简写的属性分组。
+
+ > 为什么? 因为这样能清楚地看出哪些属性使用了简写。
+
+ ```javascript
+ const anakinSkywalker = 'Anakin Skywalker';
+ const lukeSkywalker = 'Luke Skywalker';
+
+ // bad
+ const obj = {
+ episodeOne: 1,
+ twoJedisWalkIntoACantina: 2,
+ lukeSkywalker,
+ episodeThree: 3,
+ mayTheFourth: 4,
+ anakinSkywalker,
+ };
+
+ // good
+ const obj = {
+ lukeSkywalker,
+ anakinSkywalker,
+ episodeOne: 1,
+ twoJedisWalkIntoACantina: 2,
+ episodeThree: 3,
+ mayTheFourth: 4,
+ };
+ ```
+
+
+ - [3.6](#objects--quoted-props) Only quote properties that are invalid identifiers.
+ eslint: [`quote-props`](http://eslint.org/docs/rules/quote-props.html)
+ jscs: [`disallowQuotedKeysInObjects`](http://jscs.info/rule/disallowQuotedKeysInObjects)
+
+ > 为什么? In general we consider it subjectively easier to read. It improves syntax highlighting, and is also more easily optimized by many JS engines.
+
+ ```javascript
+ // bad
+ const bad = {
+ 'foo': 3,
+ 'bar': 4,
+ 'data-blah': 5,
+ };
+
+ // good
+ const good = {
+ foo: 3,
+ bar: 4,
+ 'data-blah': 5,
+ };
+ ```
+
+
+ - [3.7](#objects--prototype-builtins) Do not call `Object.prototype` methods directly, such as `hasOwnProperty`, `propertyIsEnumerable`, and `isPrototypeOf`.
+
+ > 为什么? These methods may be shadowed by properties on the object in question - consider `{ hasOwnProperty: false }` - or, the object may be a null object (`Object.create(null)`).
+
+ ```javascript
+ // bad
+ console.log(object.hasOwnProperty(key));
+
+ // good
+ console.log(Object.prototype.hasOwnProperty.call(object, key));
+
+ // best
+ const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
+ /* or */
+ import has from 'has';
+ …
+ console.log(has.call(object, key));
+ ```
+
+
+ - [3.8](#objects--rest-spread) Prefer the object spread operator over [`Object.assign`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) to shallow-copy objects. Use the object rest operator to get a new object with certain properties omitted.
+
+ ```javascript
+ // very bad
+ const original = { a: 1, b: 2 };
+ const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
+ delete copy.a; // so does this
+
+ // bad
+ const original = { a: 1, b: 2 };
+ const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
+
+ // good
+ const original = { a: 1, b: 2 };
+ const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
+
+ const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 数组
+
+
+ - [4.1](#arrays--literals) 使用字面值创建数组。
+ eslint: [`no-array-constructor`](http://eslint.org/docs/rules/no-array-constructor.html)
+
+ ```javascript
+ // bad
+ const items = new Array();
+
+ // good
+ const items = [];
+ ```
+
+
+ - [4.2](#arrays--push) 向数组添加元素时使用 [Array#push](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/push) 替代直接赋值。
+
+ ```javascript
+ const someStack = [];
+
+ // bad
+ someStack[someStack.length] = 'abracadabra';
+
+ // good
+ someStack.push('abracadabra');
+ ```
+
+
+ - [4.3](#es6-array-spreads) 使用拓展运算符 `...` 复制数组。
+
+ ```javascript
+ // bad
+ const len = items.length;
+ const itemsCopy = [];
+ let i;
+
+ for (i = 0; i < len; i++) {
+ itemsCopy[i] = items[i];
+ }
+
+ // good
+ const itemsCopy = [...items];
+
+ // ES5 中,当你需要拷贝数组时使用slice. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7)
+ // old
+ itemsCopy = items.slice();
+ ```
+
+
+ - [4.4](#arrays--from) 使用 [Array.from](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from) 把一个类数组对象转换成数组。
+
+ ```javascript
+ const foo = document.querySelectorAll('.foo');
+ const nodes = Array.from(foo);
+
+ // ES5 中使用slice将类数组的对象转成数组.
+ // old
+ function trigger() {
+ var args = Array.prototype.slice.call(arguments);
+ ...
+ }
+ ```
+
+
+ - [4.5](#arrays--callback-return) 在回调函数中使用 return 语句。如果函数体只由一个单独的语句组成,可以省略 return 关键字 [8.2](#8.2).
+ eslint: [`array-callback-return`](http://eslint.org/docs/rules/array-callback-return)
+
+ ```javascript
+ // good
+ [1, 2, 3].map((x) => {
+ const y = x + 1;
+ return x * y;
+ });
+
+ // good
+ [1, 2, 3].map(x => x + 1);
+
+ // bad
+ const flat = {};
+ [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
+ const flatten = memo.concat(item);
+ flat[index] = flatten;
+ });
+
+ // good
+ const flat = {};
+ [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
+ const flatten = memo.concat(item);
+ flat[index] = flatten;
+ return flatten;
+ });
+
+ // bad
+ inbox.filter((msg) => {
+ const { subject, author } = msg;
+ if (subject === 'Mockingbird') {
+ return author === 'Harper Lee';
+ } else {
+ return false;
+ }
+ });
+
+ // good
+ inbox.filter((msg) => {
+ const { subject, author } = msg;
+ if (subject === 'Mockingbird') {
+ return author === 'Harper Lee';
+ }
+
+ return false;
+ });
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 解构
+
+
+ - [5.1](#destructuring--object) 使用解构存取和使用多属性对象。
+ jscs: [`requireObjectDestructuring`](http://jscs.info/rule/requireObjectDestructuring)
+
+ > 为什么? 因为解构能减少临时引用属性。
+
+ ```javascript
+ // bad
+ function getFullName(user) {
+ const firstName = user.firstName;
+ const lastName = user.lastName;
+
+ return `${firstName} ${lastName}`;
+ }
+
+ // good
+ function getFullName(user) {
+ const { firstName, lastName } = user;
+ return `${firstName} ${lastName}`;
+ }
+
+ // best
+ function getFullName({ firstName, lastName }) {
+ return `${firstName} ${lastName}`;
+ }
+ ```
+
+
+ - [5.2](#destructuring--array) 对数组使用解构赋值。
+ jscs: [`requireArrayDestructuring`](http://jscs.info/rule/requireArrayDestructuring)
+
+ ```javascript
+ const arr = [1, 2, 3, 4];
+
+ // bad
+ const first = arr[0];
+ const second = arr[1];
+
+ // good
+ const [first, second] = arr;
+ ```
+
+
+ - [5.3](#destructuring--object-over-array) 需要回传多个值时,使用对象解构,而不是数组解构。
+ jscs: [`disallowArrayDestructuringReturn`](http://jscs.info/rule/disallowArrayDestructuringReturn)
+
+ > 为什么? 增加属性或者改变排序不会改变调用时的位置。
+
+ ```javascript
+ // bad
+ function processInput(input) {
+ // then a miracle occurs
+ return [left, right, top, bottom];
+ }
+
+ // 调用时需要考虑回调数据的顺序。
+ const [left, __, top] = processInput(input);
+
+ // good
+ function processInput(input) {
+ // then a miracle occurs
+ return { left, right, top, bottom };
+ }
+
+ // 调用时只选择需要的数据
+ const { left, top } = processInput(input);
+ ```
+
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## Strings
+
+
+ - [6.1](#strings--quotes) 字符串使用单引号 `''` 。
+ eslint: [`quotes`](http://eslint.org/docs/rules/quotes.html)
+ jscs: [`validateQuoteMarks`](http://jscs.info/rule/validateQuoteMarks)
+
+ ```javascript
+ // bad
+ const name = "Capt. Janeway";
+
+ // bad - template literals should contain interpolation or newlines
+ const name = `Capt. Janeway`;
+
+ // good
+ const name = 'Capt. Janeway';
+ ```
+
+
+ - [6.2](#strings--line-length) 字符串超过 100 个字节应该使用字符串连接号换行。此处可以更多个字符200或300,目前编辑界面越来越大了
+
+ > 为什么? 切断长字符串,可以更好编码和搜索。
+
+ 注:过度使用字串连接符号可能会对性能造成影响。[jsPerf](http://jsperf.com/ya-string-concat) 和 [讨论](https://github.com/airbnb/javascript/issues/40).
+
+ ```javascript
+ // bad
+ 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.';
+
+ // bad
+ 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.';
+
+ // good
+ 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.';
+ ```
+
+
+
+ - [6.3](#es6-template-literals) 程序化生成字符串时,使用模板字符串代替字符串连接。
+ eslint: [`prefer-template`](http://eslint.org/docs/rules/prefer-template.html) [`template-curly-spacing`](http://eslint.org/docs/rules/template-curly-spacing)
+ jscs: [`requireTemplateStrings`](http://jscs.info/rule/requireTemplateStrings)
+
+ > 为什么? 模板字符串插值更为简洁,更具可读性。
+
+ ```javascript
+ // bad
+ function sayHi(name) {
+ return 'How are you, ' + name + '?';
+ }
+
+ // bad
+ function sayHi(name) {
+ return ['How are you, ', name, '?'].join();
+ }
+
+ // bad
+ function sayHi(name) {
+ return `How are you, ${ name }?`;
+ }
+
+ // good
+ function sayHi(name) {
+ return `How are you, ${name}?`;
+ }
+ ```
+
+
+ - [6.4](#strings--eval) 在字符串中永不使用 `eval()`, 它会导致很多漏洞。
+
+
+ - [6.5](#strings--escaping) 字符串中不要使用不必要的转义。
+ eslint: [`no-useless-escape`](http://eslint.org/docs/rules/no-useless-escape)
+
+ > 为什么? 反斜杠会降低可读性,应该在必要时才去使用它。
+
+ ```javascript
+ // bad
+ const foo = '\'this\' \i\s \"quoted\"';
+
+ // good
+ const foo = '\'this\' is "quoted"';
+ const foo = `'this' is "quoted"`;
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 函数
+
+ - [7.1](#7.1) 使用函数表达式,而不是函数声明。
+ eslint: [`func-style`](http://eslint.org/docs/rules/func-style)
+ jscs: [`requireFunctionDeclarations`](http://jscs.info/rule/requireFunctionDeclarations)
+
+ > 为什么? 函数声明会把整个函数提升(hoisted),这导致非常容易在定义以前就被引用,这会降低可读性以及维护性(而函数表达式只会把函数的引用变量名提升)。如果发现一个函数定义非常大或复杂,会干扰其他逻辑的理解,此时也许是时候把它提取成独立模块了。
+ > 另外不要忘记给匿名表达式命名,匿名函数会使错误堆栈中跟踪问题更加困难。
+ > 函数提升规则,使得[箭头函数](#arrow-functions)可以取代函数表达式。
+
+ ```javascript
+ // bad 匿名函数表达式
+ var anonymous = function() () {
+ };
+
+ // bad
+ function foo() {
+ }
+
+ // good
+ const foo = function named() {
+ };
+ ```
+
+
+ - [7.2](#functions--iife) 用括号包裹 立即调用函数表达式(IIFE)。
+ eslint: [`wrap-iife`](http://eslint.org/docs/rules/wrap-iife.html)
+ jscs: [`requireParenthesesAroundIIFE`](http://jscs.info/rule/requireParenthesesAroundIIFE)
+
+ ```javascript
+ // 立即调用的函数表达式 (IIFE)
+ // 可使用箭头函数
+ (() => {
+ console.log('Welcome to the Internet. Please follow me.');
+ }());
+ ```
+
+
+ - [7.3](#functions--in-blocks) 永远不要在一个非函数代码块(`if`、`while` 等)中声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但它们的解析表现不一致。
+ eslint: [`no-loop-func`](http://eslint.org/docs/rules/no-loop-func.html)
+
+
+ - [7.4](#functions--note-on-blocks) **注意:** ECMA-262 把 `block` 定义为一组语句。函数声明不是语句。[阅读 ECMA-262 关于这个问题的说明](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97)。
+
+ ```javascript
+ // bad
+ if (currentUser) {
+ function test() {
+ console.log('Nope.');
+ }
+ }
+
+ // good
+ let test;
+ if (currentUser) {
+ test = () => {
+ console.log('Yup.');
+ };
+ }
+ ```
+
+
+ - [7.5](#functions--arguments-shadow) 永远不要把参数命名为 `arguments`。这将取代原来函数作用域内的 `arguments` 对象。
+
+ ```javascript
+ // bad
+ function nope(name, options, arguments) {
+ // ...stuff...
+ }
+
+ // good
+ function yup(name, options, args) {
+ // ...stuff...
+ }
+ ```
+
+
+ - [7.6](#es6-rest) 不要使用 `arguments`。可以选择 rest 语法 `...` 替代。
+ eslint: [`prefer-rest-params`](http://eslint.org/docs/rules/prefer-rest-params)
+
+ > 为什么? 使用 `...` 能明确你要传入的参数。另外 rest 参数是一个真正的数组,而 `arguments` 是一个类数组。
+
+ ```javascript
+ // bad
+ function concatenateAll() {
+ const args = Array.prototype.slice.call(arguments);
+ return args.join('');
+ }
+
+ // good
+ function concatenateAll(...args) {
+ return args.join('');
+ }
+ ```
+
+
+ - [7.7](#es6-default-parameters) 直接给函数的参数指定默认值,不要使用一个变化的函数参数。
+
+ ```javascript
+ // really bad
+ function handleThings(opts) {
+ // 不!我们不应该改变函数参数。
+ // 更加糟糕: 如果参数 opts 是 false 的话,它就会被设定为一个对象。
+ // 但这样的写法会造成一些 Bugs。
+ //(译注:例如当 opts 被赋值为空字符串,opts 仍然会被下一行代码设定为一个空对象。)
+ opts = opts || {};
+ // ...
+ }
+
+ // still bad
+ function handleThings(opts) {
+ if (opts === void 0) {
+ opts = {};
+ }
+ // ...
+ }
+
+ // good
+ function handleThings(opts = {}) {
+ // ? 对比以上写法区别是啥?参见 es6
+ // ...
+ }
+ ```
+
+
+ - [7.8](#functions--default-side-effects) 函数参数设置默认值,要避免副作用。
+
+ > 为什么? 因为这样会让人感到很困惑。
+
+ ```javascript
+ var b = 1;
+ // bad
+ function count(a = b++) {
+ console.log(a);
+ }
+ count(); // 1
+ count(); // 2
+ count(3); // 3
+ count(); // 3
+ ```
+
+
+ - [7.9](#functions--defaults-last) 总是把默认参数最后。
+
+ ```javascript
+ // bad
+ function handleThings(opts = {}, name) {
+ // ...
+ }
+
+ // good
+ function handleThings(name, opts = {}) {
+ // ...
+ }
+ ```
+
+
+ - [7.10](#functions--constructor) 永远不要使用构造函数创建新函数。
+ eslint: [`no-new-func`](http://eslint.org/docs/rules/no-new-func)
+
+ > 为什么? 以这种方式创建一个函数,类似 eval(),会导致很多漏洞。
+
+ ```javascript
+ // bad
+ var add = new Function('a', 'b', 'return a + b');
+
+ // still bad
+ var subtract = Function('a', 'b', 'return a - b');
+ ```
+
+
+ - [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)
+
+ > 为什么? 一致性好,当添加或移除名称时,不必添加或移除空间。
+
+ ```javascript
+ // bad
+ const f = function(){};
+ const g = function (){};
+ const h = function() {};
+
+ // good
+ const x = function () {};
+ const y = function a() {};
+ ```
+
+
+ - [7.12](#functions--mutate-params) 不要使用变异参数。
+ eslint: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign.html)
+
+ > 为什么? 操纵传入的参数,在原调用者上可能会导致不必要的变量副作用。
+
+ ```javascript
+ // bad
+ function f1(obj) {
+ obj.key = 1;
+ };
+
+ // good
+ function f2(obj) {
+ const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
+ };
+ ```
+
+
+ - [7.13](#functions--reassign-params) 不要给形参重新赋值。
+ eslint: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign.html)
+
+ > 为什么? 这样做可能会导致意外行为,特别是操作 `arguments` 参数。这也会导致优化问题,特别是使用 V8 解析器.
+
+ ```javascript
+ // bad
+ function f1(a) {
+ a = 1;
+ }
+
+ function f2(a) {
+ if (!a) { a = 1; }
+ }
+
+ // good
+ function f3(a) {
+ const b = a || 1;
+ }
+
+ function f4(a = 1) {
+ }
+ ```
+
+
+ - [7.14](#functions--spread-vs-apply) 使用拓展操作符 `...` 调用可变参函数。
+ eslint: [`prefer-spread`](http://eslint.org/docs/rules/prefer-spread)
+
+ > 为什么? 更简洁、并且也不用提供上下文作用域,而使用 `new` 和 `apply` 也没这个容易。
+
+ ```javascript
+ // bad
+ const x = [1, 2, 3, 4, 5];
+ console.log.apply(console, x);
+
+ // good
+ const x = [1, 2, 3, 4, 5];
+ console.log(...x);
+
+ // bad
+ new (Function.prototype.bind.apply(Date, [null, 2016, 08, 05]));
+
+ // good
+ new Date(...[2016, 08, 05]);
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 箭头函数
+
+
+ - [8.1](#arrows--use-them) 当你必须使用函数表达式(或传递一个匿名函数)时,使用箭头函数符号。
+ eslint: [`prefer-arrow-callback`](http://eslint.org/docs/rules/prefer-arrow-callback.html), [`arrow-spacing`](http://eslint.org/docs/rules/arrow-spacing.html)
+ jscs: [`requireArrowFunctions`](http://jscs.info/rule/requireArrowFunctions)
+
+ > 为什么? 因为箭头函数会创建一个你通常最想要的 `this` 执行环境,而且语法也更简洁(译注:参考 [Arrow functions - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) 和 [ES6 arrow functions, syntax and lexical scoping](http://toddmotto.com/es6-arrow-functions-syntaxes-and-lexical-scoping/)),通常情况下都能满足你的需求,而且这样的写法更为简洁。
+
+ > 为什么不?如果你有一个相当复杂的函数,你或许可以把逻辑部分转移到一个函数声明上。
+
+ ```javascript
+ // bad
+ [1, 2, 3].map(function (x) {
+ const y = x + 1;
+ return x * y;
+ });
+
+ // good
+ [1, 2, 3].map((x) => {
+ const y = x + 1;
+ return x * y;
+ });
+ ```
+
+
+ - [8.2](#arrows--implicit-return) 如果一个函数适合用一行写出并且只有一个参数,那就把花括号、圆括号和 `return` 都省略掉。如果不是,那就不要省略。
+
+ > 为什么? 这是语法糖。在链式调用中可读性很高。
+
+ > 为什么不?当你打算回传一个对象的时候。
+
+ ```javascript
+ // bad
+ [1, 2, 3].map(number => {
+ const nextNumber = number + 1;
+ `A string containing the ${nextNumber}.`;
+ });
+
+ // good
+ [1, 2, 3].map(number => `A string containing the ${number}.`);
+
+ // good
+ [1, 2, 3].map((number) => {
+ const nextNumber = number + 1;
+ return `A string containing the ${nextNumber}.`;
+ });
+
+ // good
+ [1, 2, 3].map((number, index) => ({
+ [index]: number
+ }));
+ ```
+
+
+ - [8.3](#arrows--paren-wrap) 如果表达式有多行,使用圆括号包裹,提高可读性。
+
+ > 为什么? 这样能更清楚的看到开始和结束位置。
+
+ ```js
+ // bad
+ ['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call(
+ httpMagicObjectWithAVeryLongName,
+ httpMethod
+ )
+ );
+
+ // good
+ ['get', 'post', 'put'].map(httpMethod => (
+ Object.prototype.hasOwnProperty.call(
+ httpMagicObjectWithAVeryLongName,
+ httpMethod
+ )
+ ));
+ ```
+
+
+ - [8.4](#arrows--one-arg-parens) 如果函数只有一个参数就不要使用圆括号,否则总是用圆括号包裹参数。
+ eslint: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html)
+ jscs: [`disallowParenthesesAroundArrowParam`](http://jscs.info/rule/disallowParenthesesAroundArrowParam)
+
+ > 为什么? 更少的视觉干扰
+
+ ```js
+ // bad
+ [1, 2, 3].map((x) => x * x);
+
+ // good
+ [1, 2, 3].map(x => x * x);
+
+ // good
+ [1, 2, 3].reduce((total, n) => {
+ return total + n;
+ }, 0);
+
+ // good
+ [1, 2, 3].map(number => (
+ `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
+ ));
+
+ // bad
+ [1, 2, 3].map(x => {
+ const y = x + 1;
+ return x * y;
+ });
+
+ // good
+ [1, 2, 3].map((x) => {
+ const y = x + 1;
+ return x * y;
+ });
+ ```
+
+
+ - [8.5](#arrows--confusing) 避免使用比较操作符 (`<=`, `>=`),会混淆 箭头函数语法 (`=>`)
+ eslint: [`no-confusing-arrow`](http://eslint.org/docs/rules/no-confusing-arrow)
+
+ ```js
+ // bad
+ const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize;
+
+ // bad
+ const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize;
+
+ // good
+ const itemHeight = item => (item.height > 256 ? item.largeSize : item.smallSize);
+
+ // good
+ const itemHeight = (item) => {
+ const { height, largeSize, smallSize } = item;
+ return height > 256 ? largeSize : smallSize;
+ };
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 类 & 构造器
+
+
+ - [9.1](#constructors--use-class) 总是使用 `class`。避免直接操作 `prototype` 。
+
+ > 为什么? 因为 `class` 语法更为简洁更易读。
+
+ ```javascript
+ // bad
+ function Queue(contents = []) {
+ this.queue = [...contents];
+ }
+ Queue.prototype.pop = function () {
+ const value = this.queue[0];
+ this.queue.splice(0, 1);
+ return value;
+ };
+
+
+ // good
+ class Queue {
+ constructor(contents = []) {
+ this.queue = [...contents];
+ }
+ pop() {
+ const value = this.queue[0];
+ this.queue.splice(0, 1);
+ return value;
+ }
+ }
+ ```
+
+
+ - [9.2](#constructors--extends) 使用 `extends` 继承。
+
+ > 为什么? 因为 `extends` 是一个内建的原型继承方法并且不会破坏 `instanceof`。
+
+ ```javascript
+ // bad
+ const inherits = require('inherits');
+ function PeekableQueue(contents) {
+ Queue.apply(this, contents);
+ }
+ inherits(PeekableQueue, Queue);
+ PeekableQueue.prototype.peek = function () {
+ return this.queue[0];
+ }
+
+ // good
+ class PeekableQueue extends Queue {
+ peek() {
+ return this.queue[0];
+ }
+ }
+ ```
+
+
+ - [9.3](#constructors--chaining) 方法可以返回 `this` 以便于链式调用。
+
+ ```javascript
+ // bad
+ Jedi.prototype.jump = function () {
+ this.jumping = true;
+ return true;
+ };
+
+ Jedi.prototype.setHeight = function (height) {
+ this.height = height;
+ };
+
+ const luke = new Jedi();
+ luke.jump(); // => true
+ luke.setHeight(20); // => undefined
+
+ // good
+ class Jedi {
+ jump() {
+ this.jumping = true;
+ return this;
+ }
+
+ setHeight(height) {
+ this.height = height;
+ return this;
+ }
+ }
+
+ const luke = new Jedi();
+
+ luke.jump()
+ .setHeight(20);
+ ```
+
+
+
+ - [9.4](#constructors--tostring) 可以自定义 `toString()` 方法,但要确保它能正常运行并且不会引起副作用。
+
+ ```javascript
+ class Jedi {
+ constructor(options = {}) {
+ this.name = options.name || 'no name';
+ }
+
+ getName() {
+ return this.name;
+ }
+
+ toString() {
+ return `Jedi - ${this.getName()}`;
+ }
+ }
+ ```
+
+
+ - [9.5](#constructors--no-useless) 类有默认构造函数,书写一个空的构造函数是没必要的。
+ eslint: [`no-useless-constructor`](http://eslint.org/docs/rules/no-useless-constructor)
+
+ ```javascript
+ // bad
+ class Jedi {
+ constructor() {}
+
+ getName() {
+ return this.name;
+ }
+ }
+
+ // bad
+ class Rey extends Jedi {
+ constructor(...args) {
+ super(...args);
+ }
+ }
+
+ // good
+ class Rey extends Jedi {
+ constructor(...args) {
+ super(...args);
+ this.name = 'Rey';
+ }
+ }
+ ```
+
+
+ - [9.6](#classes--no-duplicate-members) 避免类成员重复。
+ eslint: [`no-dupe-class-members`](http://eslint.org/docs/rules/no-dupe-class-members)
+
+ > 为什么? 重复的类成员默认会使用最后一个——这肯定有一个错误存在。
+
+ ```javascript
+ // bad
+ class Foo {
+ bar() { return 1; }
+ bar() { return 2; }
+ }
+
+ // good
+ class Foo {
+ bar() { return 1; }
+ }
+
+ // good
+ class Foo {
+ bar() { return 2; }
+ }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 模块
+
+
+ - [10.1](#modules--use-them) 总是使用模块 (`import`/`export`) 而不是其他非标准模块系统。你可以编译为你喜欢的模块系统。
+
+ > 为什么? 模块就是未来,让我们开始迈向未来吧。
+ > NOTE: 模块命名?(这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致)
+
+ ```javascript
+ // bad
+ const AirbnbStyleGuide = require('./AirbnbStyleGuide');
+ module.exports = AirbnbStyleGuide.es6;
+
+ // ok
+ import AirbnbStyleGuide from './AirbnbStyleGuide';
+ export default AirbnbStyleGuide.es6;
+
+ // best
+ import { es6 } from './AirbnbStyleGuide';
+ export default es6;
+
+ // ES5中要注意
+ // old
+ // - 模块应该以 `!` 开始,这保证了如果一个有问题的模块忘记包含最后的分号在合并后不会出现错误
+ // - 这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致
+ // - 加入一个名为noConflict()的方法来设置导出的模块为之前的版本并返回它
+ // - 总是在模块顶部声明 `'use strict';`
+ ```
+
+
+ - [10.2](#modules--no-wildcard) 不要使用通配符 import。
+
+ > 为什么? 这样能确保你只有一个默认 export。
+
+ ```javascript
+ // bad
+ import * as AirbnbStyleGuide from './AirbnbStyleGuide';
+
+ // good
+ import AirbnbStyleGuide from './AirbnbStyleGuide';
+ ```
+
+
+ - [10.3](#modules--no-export-from-import) 不要从 import 中直接 export。
+
+ > 为什么? 虽然一行代码简洁明了,但让 import 和 export 各司其职让事情能保持一致。
+
+ ```javascript
+ // bad
+ // filename es6.js
+ export { es6 as default } from './AirbnbStyleGuide';
+
+ // good
+ // filename es6.js
+ import { es6 } from './AirbnbStyleGuide';
+ export default es6;
+ ```
+
+
+ - [10.4](#modules--no-duplicate-imports) 一个模块只要一个 `import` 。
+ eslint: [`no-duplicate-imports`](http://eslint.org/docs/rules/no-duplicate-imports)
+
+ > 为什么? 同一模块多个 `import` 导入,会使代码更难维护。
+
+ ```javascript
+ // bad
+ import foo from 'foo';
+ // … some other imports … //
+ import { named1, named2 } from 'foo';
+
+ // good
+ import foo, { named1, named2 } from 'foo';
+
+ // good
+ import foo, {
+ named1,
+ named2,
+ } from 'foo';
+ ```
+
+
+ - [10.5](#modules--no-mutable-exports) 禁止 `export` 可写值输出,使用常量(Functions/Classes 暂时例外)。
+ eslint: [`import/no-mutable-exports`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md)
+
+ > 为什么? 避免全局使用时出现问题,除了某些特定情况下确实要这样用。一般来说,`export` 应该输出常量。
+
+ ```javascript
+ // bad
+ var count = 3;
+ export { count }
+
+ // bad
+ let foo = 3;
+ export { foo }
+
+ // good
+ const foo = 3;
+ export { foo }
+
+ // valid
+ export const count = 1
+ export function getCount () {}
+ export class Counter {}
+ ```
+
+
+ - [10.6](#modules--prefer-default-export) 单出口模块,更倾向设置为默认出口。
+eslint: [`import/prefer-default-export`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md)
+
+ ```javascript
+ // bad
+ export function foo() {}
+
+ // good
+ export default function foo() {}
+ ```
+
+
+ - [10.7](#modules--imports-first) 把所有的 `import` 语句放在其他语句上面
+eslint: [`import/imports-first`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/imports-first.md)
+
+ > 为什么? 把 `import` 提升, 保持将它们写在文件顶部是个好习惯。
+
+ ```javascript
+ // bad
+ import foo from 'foo';
+ foo.init();
+
+ import bar from 'bar';
+
+ // good
+ import foo from 'foo';
+ import bar from 'bar';
+
+ foo.init();
+ ```
+
+
+ - [10.8](#modules--multiline-imports-over-newlines) 多 `import` 入口,代码书写格式应与 `array` 和 `object` 保持一致。
+
+ > 为什么? 大括号代码块、缩进以及逗号都保持风格一致
+
+ ```javascript
+ // bad
+ import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
+
+ // good
+ import {
+ longNameA,
+ longNameB,
+ longNameC,
+ longNameD,
+ longNameE,
+ } from 'path';
+ ```
+
+
+ - [10.9](#modules--no-webpack-loader-syntax) 不允许在 `import` 语句里包含 webpack 加载器语法。
+eslint: [`import/no-webpack-loader-syntax`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-webpack-loader-syntax.md)
+
+ > 为什么? 加载器语法要在 `webpack.config.js` 中使用
+
+ ```javascript
+ // bad
+ import fooSass from 'css!sass!foo.scss';
+ import barCss from 'style!css!bar.css';
+
+ // good
+ import fooSass from 'foo.scss';
+ import barCss from 'bar.css';
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## Iterators and Generators 迭代器 & 生成器
+
+
+ - [11.1](#iterators--nope) 不要使用 iterators。使用高阶函数例如 `map()` 和 `reduce()` 替代 `for-in` or `for-of`。
+ eslint: [`no-iterator`](http://eslint.org/docs/rules/no-iterator.html) [`no-restricted-syntax`](http://eslint.org/docs/rules/no-restricted-syntax)
+
+ > 为什么? 这加强了我们不变的规则。处理纯函数的回调值更易读,这比它带来的副作用更重要。
+
+ > 使用迭代器 `map()` / `every()` / `filter()` / `find()` / `findIndex()` / `reduce()` / `some()` / ... 遍历数组,使用 `Object.keys()` / `Object.values()` / `Object.entries()` 遍历对象。
+ ```javascript
+ const numbers = [1, 2, 3, 4, 5];
+
+ // bad
+ let sum = 0;
+ for (let num of numbers) {
+ sum += num;
+ }
+ sum === 15;
+
+ // good
+ let sum = 0;
+ numbers.forEach(num => sum += num);
+ sum === 15;
+
+ // best (use the functional force)
+ const sum = numbers.reduce((total, num) => total + num, 0);
+ sum === 15;
+ ```
+
+
+ - [11.2](#generators--nope) 现在还不要使用生成器 generators。
+
+ > 为什么? 因为它们现在还没法很好地编译到 ES5。 (译者注:目前(2016/03) Chrome 和 Node.js 的稳定版本都已支持 generators)
+
+
+ - [11.3](#generators--spacing) 如果你必须使用generators 或无视[generators 忠告](#generators--nope),那么请务必确保函数签名(function*)是适当的间距。
+ eslint: [`generator-star-spacing`](http://eslint.org/docs/rules/generator-star-spacing)
+
+ > 为什么? `function` and `*` 是同一个关键词的不同组成部分—— `*` 不是 `function` 修饰符, `function*` 是一种特定结构, 不同于 `function`。
+
+ ```js
+ // bad
+ function * foo() {
+ }
+
+ const bar = function * () {
+ }
+
+ const baz = function *() {
+ }
+
+ const quux = function*() {
+ }
+
+ function*foo() {
+ }
+
+ function *foo() {
+ }
+
+ // very bad
+ function
+ *
+ foo() {
+ }
+
+ const wat = function
+ *
+ () {
+ }
+
+ // good
+ function* foo() {
+ }
+
+ const foo = function* () {
+ }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 属性
+
+
+ - [12.1](#properties--dot) 使用 `.` 符号来访问对象的属性。
+ eslint: [`dot-notation`](http://eslint.org/docs/rules/dot-notation.html)
+ jscs: [`requireDotNotation`](http://jscs.info/rule/requireDotNotation)
+
+ ```javascript
+ const luke = {
+ jedi: true,
+ age: 28,
+ };
+
+ // bad
+ const isJedi = luke['jedi'];
+
+ // good
+ const isJedi = luke.jedi;
+ ```
+
+
+ - [12.2](#properties--bracket) 当通过变量访问属性时使用中括号 `[]`。
+
+ ```javascript
+ const luke = {
+ jedi: true,
+ age: 28,
+ };
+
+ function getProp(prop) {
+ return luke[prop];
+ }
+
+ const isJedi = getProp('jedi');
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 变量
+
+
+ - [13.1](#variables--const) 总是使用 `const` 来声明变量,如果不这样做就会产生全局变量。我们需要避免全局命名空间的污染。[地球队长](http://www.wikiwand.com/en/Captain_Planet)已经警告过我们了。
+ (译注:全局,global 亦有全球的意思。地球队长的责任是保卫地球环境,所以他警告我们不要造成「全球」污染。)
+ eslint: [`no-undef`](http://eslint.org/docs/rules/no-undef) [`prefer-const`](http://eslint.org/docs/rules/prefer-const)
+
+ ```javascript
+ // bad
+ superPower = new SuperPower();
+
+ // good
+ const superPower = new SuperPower();
+ ```
+
+
+ - [13.2](#variables--one-const) 使用 `const` 声明每一个变量。
+ eslint: [`one-var`](http://eslint.org/docs/rules/one-var.html) jscs: [`disallowMultipleVarDecl`](http://jscs.info/rule/disallowMultipleVarDecl)
+
+ > 为什么? 增加新变量将更容易,而且你永远不用再担心调换错 `;` or `,` ,并且 diff 工具下更少干扰。同时在 debugger 时,可以单步调试而不会一次跳过他们所有变量。
+
+ ```javascript
+ // bad
+ const items = getItems(),
+ goSportsTeam = true,
+ dragonball = 'z';
+
+ // bad
+ // (compare to above, and try to spot the mistake)
+ const items = getItems(),
+ goSportsTeam = true;
+ dragonball = 'z';
+
+ // good
+ const items = getItems();
+ const goSportsTeam = true;
+ const dragonball = 'z';
+ ```
+
+
+ - [13.3](#variables--const-let-group) 将所有的 `const` 和 `let` 分组
+
+ > 为什么? 当你需要把已赋值变量赋值给未赋值变量时非常有用。
+
+ ```javascript
+ // bad
+ let i, len, dragonball,
+ items = getItems(),
+ goSportsTeam = true;
+
+ // bad
+ let i;
+ const items = getItems();
+ let dragonball;
+ const goSportsTeam = true;
+ let len;
+
+ // good
+ const goSportsTeam = true;
+ const items = getItems();
+ let dragonball;
+ let i;
+ let length;
+ ```
+
+
+ - [13.4](#variables--define-where-used) 在你需要的地方给变量赋值,但请把它们放在一个合理的位置。
+
+ > 为什么? `let` 和 `const` 是块级作用域而不是函数作用域。
+
+ ```javascript
+ // bad - unnecessary function call
+ function checkName(hasName) {
+ const name = getName();
+
+ if (hasName === 'test') {
+ return false;
+ }
+
+ if (name === 'test') {
+ this.setName('');
+ return false;
+ }
+
+ return name;
+ }
+
+ // good
+ function checkName(hasName) {
+ if (hasName === 'test') {
+ return false;
+ }
+
+ const name = getName();
+
+ if (name === 'test') {
+ this.setName('');
+ return false;
+ }
+
+ return name;
+ }
+ ```
+
+
+ - [13.5](#variables--no-chain-assignment) 不使用链接变量赋值。
+
+ > 为什么? 链接变量赋值会创建隐式全局变量。
+
+ ```javascript
+ // bad
+ (function example() {
+ // JavaScript interprets this as
+ // let a = ( b = ( c = 1 ) );
+ // The let keyword only applies to variable a; variables b and c become
+ // global variables.
+ let a = b = c = 1;
+ }());
+
+ console.log(a); // undefined
+ console.log(b); // 1
+ console.log(c); // 1
+
+ // good
+ (function example() {
+ let a = 1;
+ let b = a;
+ let c = a;
+ }());
+
+ console.log(a); // undefined
+ console.log(b); // undefined
+ console.log(c); // undefined
+
+ // the same applies for `const`
+ ```
+
+
+ - [13.6](#variables--unary-increment-decrement) 便面使用一元递增和递减操作 (++, --) 。
+ eslint [`no-plusplus`](http://eslint.org/docs/rules/no-plusplus)
+
+ > 为什么? 一元递增和递减语句默认在自动分号插入处理下会有错误问题。而且它还会出现 `num += 1` 替代 `num ++` 的情况。不允许使用它们,也可以代码更健壮。
+
+ ```javascript
+ // bad
+
+ let array = [1, 2, 3];
+ let num = 1;
+ num ++;
+ -- num;
+
+ let sum = 0;
+ let truthyCount = 0;
+ for(let i = 0; i < array.length; i++){
+ let value = array[i];
+ sum += value;
+ if (value) {
+ truthyCount++;
+ }
+ }
+
+ // good
+
+ let array = [1, 2, 3];
+ let num = 1;
+ num += 1;
+ num -= 1;
+
+ const sum = array.reduce((a, b) => a + b, 0);
+ const truthyCount = array.filter(Boolean).length;
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## Hoisting
+
+
+ - [14.1](#hoisting--about) `var` 声明会被提升至该作用域的顶部,但它们赋值不会提升。`let` 和 `const` 被赋予了一种称为「[暂时性死区(Temporal Dead Zones, TDZ)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let)」的概念。这对于了解为什么 [type of 不再安全](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15)相当重要。
+
+ ```javascript
+ // 我们知道这样运行不了(假设 notDefined 不是全局变量)
+ function example() {
+ console.log(notDefined); // => throws a ReferenceError
+ }
+
+ // 由于变量提升的原因,
+ // 在引用变量后再声明变量是可以运行的。
+ // **注意:** 变量赋值 `true` 的操作不会被提升。
+ function example() {
+ console.log(declaredButNotAssigned); // => undefined
+ var declaredButNotAssigned = true;
+ }
+
+ // 编译器会把函数声明提升到作用域的顶层,
+ // 这意味着我们的例子可以改写成这样:
+ function example() {
+ let declaredButNotAssigned;
+ console.log(declaredButNotAssigned); // => undefined
+ declaredButNotAssigned = true;
+ }
+
+ // 使用 const 和 let
+ function example() {
+ console.log(declaredButNotAssigned); // => throws a ReferenceError
+ console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
+ const declaredButNotAssigned = true;
+ }
+ ```
+
+
+ - [14.2](#hoisting--anon-expressions) 匿名函数表达式的变量名会被提升,但函数体并不会。
+
+ ```javascript
+ function example() {
+ console.log(anonymous); // => undefined
+
+ anonymous(); // => TypeError anonymous is not a function
+
+ var anonymous = function () {
+ console.log('anonymous function expression');
+ };
+ }
+ ```
+
+
+ - [14.3](#hoisting--named-expresions) 命名的函数表达式的变量名会被提升,但函数名和函数体并不会。
+
+ ```javascript
+ function example() {
+ console.log(named); // => undefined
+
+ named(); // => TypeError named is not a function
+
+ superPower(); // => ReferenceError superPower is not defined
+
+ var named = function superPower() {
+ console.log('Flying');
+ };
+ }
+
+ // the same is true when the function name
+ // is the same as the variable name.
+ function example() {
+ console.log(named); // => undefined
+
+ named(); // => TypeError named is not a function
+
+ var named = function named() {
+ console.log('named');
+ }
+ }
+ ```
+
+
+ - [14.4](#hoisting--declarations) 函数声明的名称和函数体都会被提升。
+
+ ```javascript
+ function example() {
+ superPower(); // => Flying
+
+ function superPower() {
+ console.log('Flying');
+ }
+ }
+ ```
+
+ - For more information refer to [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting/) by [Ben Cherry](http://www.adequatelygood.com/).
+
+ - 想了解更多信息,参考 [Ben Cherry](http://www.adequatelygood.com/) 的 [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting)。
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 比较运算符 & 等号
+
+
+ - [15.1](#comparison--eqeqeq) 优先使用 `===` 和 `!==` 而不是 `==` 和 `!=` 。
+ eslint: [`eqeqeq`](http://eslint.org/docs/rules/eqeqeq.html)
+
+
+ - [15.2](#comparison--if) 条件表达式例如 `if` 语句通过抽象方法 `ToBoolean` 强制计算它们的表达式并且总是遵守下面的规则:
+
+ + **Objects 对象** 被计算为 **true**
+ + **Undefined** 被计算为 **false**
+ + **Null** 被计算为 **false**
+ + **Booleans 布尔值** 被计算为 **布尔的值**
+ + **Numbers 数字** 如果是 **+0、-0、或 NaN** 被计算为 **false**, 否则为 **true**
+ + **Strings 字符串** 如果是空字符串 `''` 被计算为 **false**,否则为 **true**
+
+ ```javascript
+ if ([0] && []) {
+ // true
+ // an array (even an empty one) is an object, objects will evaluate to true
+ }
+ ```
+
+
+ - [15.3](#comparison--shortcuts) 使用简写。
+
+ ```javascript
+ // bad
+ if (isValid === true) {
+ // ...stuff...
+ }
+
+ // good
+ if (isValid) {
+ // ...stuff...
+ }
+
+ // bad
+ if (name) {
+ // ...stuff...
+ }
+
+ // good
+ if (name !== '') {
+ // ...stuff...
+ }
+
+ // bad
+ if (collection.length) {
+ // ...stuff...
+ }
+
+ // good
+ if (collection.length > 0) {
+ // 为什么没用简写???
+ // ...stuff...
+ }
+ ```
+
+
+ - [15.4](#comparison--moreinfo) 想了解更多信息,参考 Angus Croll 的 [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108)。
+
+
+ - [15.5](#comparison--switch-blocks) `case` 以及 `default` 情况下使用括号会创建块级作用域 (e.g. `let`, `const`, `function`, and `class`).
+
+ > 为什么? 变量声明在整个 `switch` 代码块中是可用的,但只有在执行到 `case` 并赋值时才初始化。多 `case` 中重复定义会导致问题。
+
+ eslint rules: [`no-case-declarations`](http://eslint.org/docs/rules/no-case-declarations.html).
+
+ ```javascript
+ // ???
+ // bad
+ switch (foo) {
+ case 1:
+ let x = 1;
+ break;
+ case 2:
+ const y = 2;
+ break;
+ case 3:
+ function f() {}
+ break;
+ default:
+ class C {}
+ }
+
+ // good
+ switch (foo) {
+ case 1: {
+ let x = 1;
+ break;
+ }
+ case 2: {
+ const y = 2;
+ break;
+ }
+ case 3: {
+ function f() {}
+ break;
+ }
+ case 4:
+ bar();
+ break;
+ default: {
+ class C {}
+ }
+ }
+ ```
+
+
+ - [15.6](#comparison--nested-ternaries) 别嵌套使用三元表达式,要单个使用。
+
+ eslint rules: [`no-nested-ternary`](http://eslint.org/docs/rules/no-nested-ternary.html).
+
+ ```javascript
+ // bad
+ const foo = maybe1 > maybe2
+ ? "bar"
+ : value1 > value2 ? "baz" : null;
+
+ // better
+ const maybeNull = value1 > value2 ? 'baz' : null;
+
+ const foo = maybe1 > maybe2
+ ? 'bar'
+ : maybeNull;
+
+ // best
+ const maybeNull = value1 > value2 ? 'baz' : null;
+
+ const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
+ ```
+
+
+ - [15.7](#comparison--unneeded-ternary) 避免不必要使用三元表达式
+
+ eslint rules: [`no-unneeded-ternary`](http://eslint.org/docs/rules/no-unneeded-ternary.html).
+
+ ```javascript
+ // bad
+ const foo = a ? a : b;
+ const bar = c ? true : false;
+ const baz = c ? false : true;
+
+ // good
+ const foo = a || b;
+ const bar = !!c;
+ const baz = !c;
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 代码块
+
+
+ - [16.1](#blocks--braces) 使用大括号包裹所有的多行代码块。
+
+ ```javascript
+ // bad
+ if (test)
+ return false;
+
+ // good
+ if (test) return false;
+
+ // good
+ if (test) {
+ return false;
+ }
+
+ // bad
+ function foo() { return false; }
+
+ // good
+ function bar() {
+ return false;
+ }
+ ```
+
+
+ - [16.2](#blocks--cuddled-elses) 如果通过 `if` 和 `else` 使用多行代码块,把 `else` 放在 `if` 代码块关闭括号的同一行。
+
+ ```javascript
+ // bad
+ if (test) {
+ thing1();
+ thing2();
+ }
+ else {
+ thing3();
+ }
+
+ // good
+ if (test) {
+ thing1();
+ thing2();
+ } else {
+ thing3();
+ }
+ ```
+
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 注释
+
+
+ - [17.1](#comments--multiline) 使用 `/** ... */` 作为多行注释。包含描述、指定所有参数和返回值的类型和值。
+
+ ```javascript
+ // bad
+ // make() returns a new element
+ // based on the passed in tag name
+ //
+ // @param {String} tag
+ // @return {Element} element
+ function make(tag) {
+
+ // ...stuff...
+
+ return element;
+ }
+
+ // good
+ /**
+ * make() returns a new element
+ * based on the passed-in tag name
+ *
+ * @param {String} tag
+ * @return {Element} element
+ */
+ function make(tag) {
+
+ // ...stuff...
+
+ return element;
+ }
+ ```
+
+
+ - [17.2](#comments--singleline) 单行注释使用 `//`,后紧跟一空格。在评论对象上面另起一行使用单行注释。在注释前插入空行。
+
+ ```javascript
+ // bad
+ const active = true; // is current tab
+
+ // good
+ // is current tab
+ const active = true;
+
+ // bad
+ function getType() {
+ console.log('fetching type...');
+ // set the default type to 'no type'
+ const type = this._type || 'no type';
+
+ return type;
+ }
+
+ // good
+ function getType() {
+ console.log('fetching type...');
+
+ // set the default type to 'no type'
+ const type = this._type || 'no type';
+
+ return type;
+ }
+
+ // also good
+ function getType() {
+ // set the default type to 'no type'
+ const type = this._type || 'no type';
+
+ return type;
+ }
+ ```
+
+
+ - [17.3](#comments--actionitems) 给注释增加 `FIXME` 或 `TODO` 的前缀可以帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。这将有别于常见的注释,因为它们是可操作的。使用 `FIXME -- need to figure this out` 或者 `TODO -- need to implement`。
+
+
+ - [17.4](#comments--fixme) 使用 `// FIXME`: 标注问题。
+
+ ```javascript
+ class Calculator extends Abacus {
+ constructor() {
+ super();
+
+ // FIXME: shouldn't use a global here
+ total = 0;
+ }
+ }
+ ```
+
+
+ - [17.5](#comments--todo) 使用 `// TODO`: 标注问题还需要解决。
+
+ ```javascript
+ class Calculator extends Abacus {
+ constructor() {
+ super();
+
+ // TODO: total should be configurable by an options param
+ this.total = 0;
+ }
+ }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 空白
+
+
+ - [18.1](#whitespace--spaces) 使用 2 个空格作为缩进。
+ eslint: [`indent`](http://eslint.org/docs/rules/indent.html)
+ jscs: [`validateIndentation`](http://jscs.info/rule/validateIndentation)
+
+ ```javascript
+ // bad
+ function foo() {
+ ∙∙∙∙const name;
+ }
+
+ // bad
+ function bar() {
+ ∙const name;
+ }
+
+ // good
+ function baz() {
+ ∙∙const name;
+ }
+ ```
+
+
+ - [18.2](#whitespace--before-blocks) 在花括号前放一个空格。
+ eslint: [`space-before-blocks`](http://eslint.org/docs/rules/space-before-blocks.html)
+ jscs: [`requireSpaceBeforeBlockStatements`](http://jscs.info/rule/requireSpaceBeforeBlockStatements)
+
+ ```javascript
+ // bad
+ function test(){
+ console.log('test');
+ }
+
+ // good
+ function test() {
+ console.log('test');
+ }
+
+ // bad
+ dog.set('attr',{
+ age: '1 year',
+ breed: 'Bernese Mountain Dog',
+ });
+
+ // good
+ dog.set('attr', {
+ age: '1 year',
+ breed: 'Bernese Mountain Dog',
+ });
+ ```
+
+
+ - [18.3](#whitespace--around-keywords) 在控制语句(`if`、`while` 等)的小括号前放一个空格。在函数调用及声明中,不在函数的参数列表前加空格。
+ eslint: [`keyword-spacing`](http://eslint.org/docs/rules/keyword-spacing.html)
+ jscs: [`requireSpaceAfterKeywords`](http://jscs.info/rule/requireSpaceAfterKeywords)
+
+ ```javascript
+ // bad
+ if(isJedi) {
+ fight ();
+ }
+
+ // good
+ if (isJedi) {
+ fight();
+ }
+
+ // bad
+ function fight () {
+ console.log ('Swooosh!');
+ }
+
+ // good
+ function fight() {
+ console.log('Swooosh!');
+ }
+ ```
+
+
+ - [18.4](#whitespace--infix-ops) 使用空格把运算符隔开。
+ eslint: [`space-infix-ops`](http://eslint.org/docs/rules/space-infix-ops.html)
+ jscs: [`requireSpaceBeforeBinaryOperators`](http://jscs.info/rule/requireSpaceBeforeBinaryOperators), [`requireSpaceAfterBinaryOperators`](http://jscs.info/rule/requireSpaceAfterBinaryOperators)
+
+ ```javascript
+ // bad
+ const x=y+5;
+
+ // good
+ const x = y + 5;
+ ```
+
+
+ - [18.5](#whitespace--newline-at-end) 在文件末尾插入一个空行。
+ eslint: [`eol-last`](https://github.com/eslint/eslint/blob/master/docs/rules/eol-last.md)
+
+ ```javascript
+ // bad
+ (function (global) {
+ // ...stuff...
+ })(this);
+ ```
+
+ ```javascript
+ // bad
+ (function (global) {
+ // ...stuff...
+ })(this);↵
+ ↵
+ ```
+
+ ```javascript
+ // good
+ (function (global) {
+ // ...stuff...
+ })(this);↵
+ ```
+
+
+ - [18.6](#whitespace--chains) 在使用长方法链时进行缩进。以 `.` 起行并缩进,强调这是方法调用而不是新语句。
+ 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)
+
+ ```javascript
+ // bad
+ $('#items').find('.selected').highlight().end().find('.open').updateCount();
+
+ // bad
+ $('#items').
+ find('.selected').
+ highlight().
+ end().
+ find('.open').
+ updateCount();
+
+ // good
+ $('#items')
+ .find('.selected')
+ .highlight()
+ .end()
+ .find('.open')
+ .updateCount();
+
+ // bad
+ const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
+ .attr('width', (radius + margin) * 2).append('svg:g')
+ .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
+ .call(tron.led);
+
+ // good
+ const leds = stage.selectAll('.led')
+ .data(data)
+ .enter().append('svg:svg')
+ .classed('led', true)
+ .attr('width', (radius + margin) * 2)
+ .append('svg:g')
+ .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
+ .call(tron.led);
+
+ // good
+ const leds = stage.selectAll('.led').data(data);
+ ```
+
+
+ - [18.7](#whitespace--after-blocks) 在块末和新语句前插入空行。
+ jscs: [`requirePaddingNewLinesAfterBlocks`](http://jscs.info/rule/requirePaddingNewLinesAfterBlocks)
+
+ ```javascript
+ // bad
+ if (foo) {
+ return bar;
+ }
+ return baz;
+
+ // good
+ if (foo) {
+ return bar;
+ }
+
+ return baz;
+
+ // bad
+ const obj = {
+ foo() {
+ },
+ bar() {
+ },
+ };
+ return obj;
+
+ // good
+ const obj = {
+ foo() {
+ },
+
+ bar() {
+ },
+ };
+
+ return obj;
+
+ // bad
+ const arr = [
+ function foo() {
+ },
+ function bar() {
+ },
+ ];
+ return arr;
+
+ // good
+ const arr = [
+ function foo() {
+ },
+
+ function bar() {
+ },
+ ];
+
+ return arr;
+ ```
+
+
+ - [18.8](#whitespace--padded-blocks) Do not pad your blocks with blank lines. eslint: [`padded-blocks`](http://eslint.org/docs/rules/padded-blocks.html) jscs: [`disallowPaddingNewlinesInBlocks`](http://jscs.info/rule/disallowPaddingNewlinesInBlocks)
+
+ ```javascript
+ // bad
+ function bar() {
+
+ console.log(foo);
+
+ }
+
+ // also bad
+ if (baz) {
+
+ console.log(qux);
+ } else {
+ console.log(foo);
+
+ }
+
+ // good
+ function bar() {
+ console.log(foo);
+ }
+
+ // good
+ if (baz) {
+ console.log(qux);
+ } else {
+ console.log(foo);
+ }
+ ```
+
+
+ - [18.9](#whitespace--in-parens) Do not add spaces inside parentheses. eslint: [`space-in-parens`](http://eslint.org/docs/rules/space-in-parens.html) jscs: [`disallowSpacesInsideParentheses`](http://jscs.info/rule/disallowSpacesInsideParentheses)
+
+ ```javascript
+ // bad
+ function bar( foo ) {
+ return foo;
+ }
+
+ // good
+ function bar(foo) {
+ return foo;
+ }
+
+ // bad
+ if ( foo ) {
+ console.log(foo);
+ }
+
+ // good
+ if (foo) {
+ console.log(foo);
+ }
+ ```
+
+
+ - [18.10](#whitespace--in-brackets) Do not add spaces inside brackets. eslint: [`array-bracket-spacing`](http://eslint.org/docs/rules/array-bracket-spacing.html) jscs: [`disallowSpacesInsideArrayBrackets`](http://jscs.info/rule/disallowSpacesInsideArrayBrackets)
+
+ ```javascript
+ // bad
+ const foo = [ 1, 2, 3 ];
+ console.log(foo[ 0 ]);
+
+ // good
+ const foo = [1, 2, 3];
+ console.log(foo[0]);
+ ```
+
+
+ - [18.11](#whitespace--in-braces) Add spaces inside curly braces. eslint: [`object-curly-spacing`](http://eslint.org/docs/rules/object-curly-spacing.html) jscs: [`requireSpacesInsideObjectBrackets`](http://jscs.info/rule/requireSpacesInsideObjectBrackets)
+
+ ```javascript
+ // bad
+ const foo = {clark: 'kent'};
+
+ // good
+ const foo = { clark: 'kent' };
+ ```
+
+
+ - [18.12](#whitespace--max-len) Avoid having lines of code that are longer than 100 characters (including whitespace). Note: per [above](#strings--line-length), long strings are exempt from this rule, and should not be broken up. eslint: [`max-len`](http://eslint.org/docs/rules/max-len.html) jscs: [`maximumLineLength`](http://jscs.info/rule/maximumLineLength)
+
+ > Why? This ensures readability and maintainability.
+
+ ```javascript
+ // bad
+ const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy;
+
+ // bad
+ $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));
+
+ // good
+ const foo = jsonData
+ && jsonData.foo
+ && jsonData.foo.bar
+ && jsonData.foo.bar.baz
+ && jsonData.foo.bar.baz.quux
+ && jsonData.foo.bar.baz.quux.xyzzy;
+
+ // good
+ $.ajax({
+ method: 'POST',
+ url: 'https://airbnb.com/',
+ data: { name: 'John' },
+ })
+ .done(() => console.log('Congratulations!'))
+ .fail(() => console.log('You have failed this city.'));
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 逗号
+
+
+ - [19.1](#commas--leading-trailing) 行首逗号:**不需要**。
+ eslint: [`comma-style`](http://eslint.org/docs/rules/comma-style.html)
+ jscs: [`requireCommaBeforeLineBreak`](http://jscs.info/rule/requireCommaBeforeLineBreak)
+
+ ```javascript
+ // bad
+ const story = [
+ once
+ , upon
+ , aTime
+ ];
+
+ // good
+ const story = [
+ once,
+ upon,
+ aTime,
+ ];
+
+ // bad
+ const hero = {
+ firstName: 'Ada'
+ , lastName: 'Lovelace'
+ , birthYear: 1815
+ , superPower: 'computers'
+ };
+
+ // good
+ const hero = {
+ firstName: 'Ada',
+ lastName: 'Lovelace',
+ birthYear: 1815,
+ superPower: 'computers',
+ };
+ ```
+
+
+ - [19.2](#commas--dangling) 增加结尾的逗号: **需要**。
+ eslint: [`comma-dangle`](http://eslint.org/docs/rules/comma-dangle.html)
+ jscs: [`requireTrailingComma`](http://jscs.info/rule/requireTrailingComma)
+
+ > 为什么? 这会让 git diffs 更干净。另外,像 babel 这样的转译器会移除结尾多余的逗号,也就是说你不必担心老旧浏览器的[尾逗号问题](https://github.com/airbnb/javascript/blob/es5-deprecated/es5/README.md#commas)。
+
+ ```javascript
+ // bad - git diff without trailing comma
+ const hero = {
+ firstName: 'Florence',
+ - lastName: 'Nightingale'
+ + lastName: 'Nightingale',
+ + inventorOf: ['coxcomb chart', 'modern nursing']
+ };
+
+ // good - git diff with trailing comma
+ const hero = {
+ firstName: 'Florence',
+ lastName: 'Nightingale',
+ + inventorOf: ['coxcomb chart', 'modern nursing'],
+ };
+
+ // bad
+ const hero = {
+ firstName: 'Dana',
+ lastName: 'Scully'
+ };
+
+ const heroes = [
+ 'Batman',
+ 'Superman'
+ ];
+
+ // good
+ const hero = {
+ firstName: 'Dana',
+ lastName: 'Scully',
+ };
+
+ const heroes = [
+ 'Batman',
+ 'Superman',
+ ];
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 分号
+
+
+ - [20.1](#semicolons--required) **使用分号**
+ eslint: [`semi`](http://eslint.org/docs/rules/semi.html)
+ jscs: [`requireSemicolons`](http://jscs.info/rule/requireSemicolons)
+
+ ```javascript
+ // bad
+ (function () {
+ const name = 'Skywalker'
+ return name
+ })()
+
+ // good
+ (function () {
+ const name = 'Skywalker';
+ return name;
+ }());
+
+ // good (防止函数在两个 IIFE 合并时被当成一个参数)
+ ;(() => {
+ const name = 'Skywalker';
+ return name;
+ }());
+ ```
+
+ [Read more](https://stackoverflow.com/questions/7365172/semicolon-before-self-invoking-function/7365214%237365214).
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 类型转换
+
+
+ - [21.1](#coercion--explicit) 在语句开始时执行类型转换。
+
+
+ - [21.2](#coercion--strings) 字符串:
+
+ ```javascript
+ // => this.reviewScore = 9;
+
+ // bad
+ const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf()
+
+ // bad
+ const totalScore = this.reviewScore.toString(); // isn't guaranteed to return a string
+
+ // good
+ const totalScore = String(this.reviewScore);
+ ```
+
+
+ - [21.3](#coercion--numbers) 数字:对数字使用 `parseInt` 转换,并带上类型转换的基数。
+ eslint: [`radix`](http://eslint.org/docs/rules/radix)
+
+ ```javascript
+ const inputValue = '4';
+
+ // bad
+ const val = new Number(inputValue);
+
+ // bad
+ const val = +inputValue;
+
+ // bad
+ const val = inputValue >> 0;
+
+ // bad
+ const val = parseInt(inputValue);
+
+ // good
+ const val = Number(inputValue);
+
+ // good
+ const val = parseInt(inputValue, 10);
+ ```
+
+
+ - [21.4](#coercion--comment-deviations) 如果因为某些原因 parseInt 成为你所做的事的瓶颈而需要使用位操作解决[性能问题](http://jsperf.com/coercion-vs-casting/3)时,留个注释说清楚原因和你的目的。
+
+ ```javascript
+ // good
+ /**
+ * 使用 parseInt 导致我的程序变慢,
+ * 改成使用位操作转换数字快多了。
+ */
+ const val = inputValue >> 0;
+ ```
+
+
+ - [21.5](#coercion--bitwise) **注意:** 小心使用位操作运算符。数字会被当成 [64 位值](http://es5.github.io/#x4.3.19),但是位操作运算符总是返回 32 位的整数([参考](http://es5.github.io/#x11.7))。位操作处理大于 32 位的整数值时还会导致意料之外的行为。[关于这个问题的讨论](https://github.com/airbnb/javascript/issues/109)。最大的 32 位整数是 2,147,483,647:
+
+ ```javascript
+ 2147483647 >> 0 //=> 2147483647
+ 2147483648 >> 0 //=> -2147483648
+ 2147483649 >> 0 //=> -2147483647
+ ```
+
+
+ - [21.6](#coercion--booleans) 布尔运算:
+
+ ```javascript
+ const age = 0;
+
+ // bad
+ const hasAge = new Boolean(age);
+
+ // good
+ const hasAge = Boolean(age);
+
+ // best
+ const hasAge = !!age;
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 命名规则
+
+
+ - [22.1](#naming--descriptive) 避免单字母命名。命名应具备描述性。
+ eslint: [`id-length`](http://eslint.org/docs/rules/id-length)
+
+ ```javascript
+ // bad
+ function q() {
+ // ...stuff...
+ }
+
+ // good
+ function query() {
+ // ..stuff..
+ }
+ ```
+
+
+ - [22.2](#naming--camelCase) 使用驼峰式(camelCase、小驼峰)命名变量、对象、函数和实例。
+ eslint: [`camelcase`](http://eslint.org/docs/rules/camelcase.html)
+ jscs: [`requireCamelCaseOrUpperCaseIdentifiers`](http://jscs.info/rule/requireCamelCaseOrUpperCaseIdentifiers)
+
+ ```javascript
+ // bad
+ const OBJEcttsssss = {};
+ const this_is_my_object = {};
+ function c() {}
+
+ // good
+ const thisIsMyObject = {};
+ function thisIsMyFunction() {}
+ ```
+
+
+ - [22.3](#naming--PascalCase) 使用帕斯卡式(PascalCase、大驼峰式)命名构造函数或类。
+ eslint: [`new-cap`](http://eslint.org/docs/rules/new-cap.html)
+ jscs: [`requireCapitalizedConstructors`](http://jscs.info/rule/requireCapitalizedConstructors)
+
+ Pascal命名法:单字之间不以空格断开或连接号(-)、底线(_)连结,第一个单字首字母采用大写字母;后续单字的首字母亦用大写字母
+
+ ```javascript
+ // bad
+ function user(options) {
+ this.name = options.name;
+ }
+
+ const bad = new user({
+ name: 'nope',
+ });
+
+ // good
+ class User {
+ constructor(options) {
+ this.name = options.name;
+ }
+ }
+
+ const good = new User({
+ name: 'yup',
+ });
+ ```
+
+
+ - [22.4](#naming--leading-underscore) 不要使用尾随或前导下划线来命名私有属性。
+ eslint: [`no-underscore-dangle`](http://eslint.org/docs/rules/no-underscore-dangle.html)
+ jscs: [`disallowDanglingUnderscores`](http://jscs.info/rule/disallowDanglingUnderscores)
+
+ > 为什么? JavaScript没有在属性或方法方面的隐私权的概念。虽然一个领先的下划线是一个共同的公约,意思是“私人”,事实上,这些属性是完全公开的,因此,是你的公共API合同的一部分。这个约定可能会导致开发人员错误地认为一个变化不算是中断,或者不需要测试。TL;DR:如果你想要的东西是“私人的”,它不应该可见。
+
+ ```javascript
+ // bad
+ this.__firstName__ = 'Panda';
+ this.firstName_ = 'Panda';
+ this._firstName = 'Panda';
+
+ // good
+ this.firstName = 'Panda';
+ ```
+
+
+ - [22.5](#naming--self-this) 别保存 `this` 的引用。应使用箭头函数或函数绑定 [Function#bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)。
+ jscs: [`disallowNodeTypes`](http://jscs.info/rule/disallowNodeTypes)
+
+ ```javascript
+ // bad
+ function foo() {
+ const self = this;
+ return function () {
+ console.log(self);
+ };
+ }
+
+ // bad
+ function foo() {
+ const that = this;
+ return function () {
+ console.log(that);
+ };
+ }
+
+ // good
+ function foo() {
+ return () => {
+ console.log(this);
+ };
+ }
+ ```
+
+
+ - [22.6](#naming--filename-matches-export) 如果你的文件只输出一个类,那你的文件名必须和类名完全保持一致。
+
+ ```javascript
+ // file 1 contents
+ class CheckBox {
+ // ...
+ }
+ export default CheckBox;
+
+ // file 2 contents
+ export default function fortyTwo() { return 42; }
+
+ // file 3 contents
+ export default function insideDirectory() {}
+
+ // in some other file
+ // bad
+ import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename
+ import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export
+ import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export
+
+ // bad
+ import CheckBox from './check_box'; // PascalCase import/export, snake_case filename
+ import forty_two from './forty_two'; // snake_case import/filename, camelCase export
+ import inside_directory from './inside_directory'; // snake_case import, camelCase export
+ import index from './inside_directory/index'; // requiring the index file explicitly
+ import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly
+
+ // good
+ import CheckBox from './CheckBox'; // PascalCase export/import/filename
+ import fortyTwo from './fortyTwo'; // camelCase export/import/filename
+ import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
+ // ^ supports both insideDirectory.js and insideDirectory/index.js
+ ```
+
+
+ - [22.7](#naming--camelCase-default-export) 当你导出默认的函数时使用驼峰式命名camelCase。你的文件名必须和函数名完全保持一致。
+
+ ```javascript
+ function makeStyleGuide() {
+ }
+
+ export default makeStyleGuide;
+ ```
+
+
+ - [22.8](#naming--PascalCase-singleton) 当你导出构造函数、类、单例、函数库、空对象时使用帕斯卡式命名PascalCase。
+
+ ```javascript
+ const AirbnbStyleGuide = {
+ es6: {
+ }
+ };
+
+ export default AirbnbStyleGuide;
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 存取器
+
+
+ - [23.1](#accessors--not-required) 属性的存取函数不是必须的。
+
+
+ - [23.2](#accessors--no-getters-setters) 不要使用 getters/setters 有可能引起副作用,很难测试、维护、调试。如果你需要存取函数时使用 `getVal()` 和 `setVal(value)`。
+
+ ```javascript
+ // bad
+ class Dragon {
+ get age() {
+ // ...
+ }
+
+ set age(value) {
+ // ...
+ }
+ }
+
+ // good
+ class Dragon {
+ getAge() {
+ // ...
+ }
+
+ setAge(value) {
+ // ...
+ }
+ }
+ ```
+
+
+ - [23.3](#accessors--boolean-prefix) 如果属性或方法是布尔值,使用 `isVal()` 或 `hasVal()` 判断。
+
+ ```javascript
+ // bad
+ if (!dragon.age()) {
+ return false;
+ }
+
+ // good
+ if (!dragon.hasAge()) {
+ return false;
+ }
+ ```
+
+
+ - [23.4](#accessors--consistent) 可以创建 `get()` 和 `set()` 函数,但要保持一致。
+
+ ```javascript
+ class Jedi {
+ constructor(options = {}) {
+ const lightsaber = options.lightsaber || 'blue';
+ this.set('lightsaber', lightsaber);
+ }
+
+ set(key, val) {
+ this[key] = val;
+ }
+
+ get(key) {
+ return this[key];
+ }
+ }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 事件
+
+
+ - [24.1](#events--hash) 当给事件附加数据时(无论是 DOM 事件还是私有事件),传入一个哈希而不是原始值。这样可以让后面的贡献者增加更多数据到事件数据而无需找出并更新事件的每一个处理器。例如,不好的写法:
+
+ ```javascript
+ // bad
+ $(this).trigger('listingUpdated', listing.id);
+
+ ...
+
+ $(this).on('listingUpdated', (e, listingId) => {
+ // do something with listingId
+ });
+ ```
+
+ prefer 更好的写法:
+
+ ```javascript
+ // good
+ $(this).trigger('listingUpdated', { listingId: listing.id });
+
+ ...
+
+ $(this).on('listingUpdated', (e, data) => {
+ // do something with data.listingId
+ });
+ ```
+
+ **[⬆ 返回目录](#table-of-contents)**
+
+## jQuery
+
+
+ - [25.1](#jquery--dollar-prefix) 使用 `$` 作为存储 jQuery 对象的变量名前缀。
+ jscs: [`requireDollarBeforejQueryAssignment`](http://jscs.info/rule/requireDollarBeforejQueryAssignment)
+
+ ```javascript
+ // bad
+ const sidebar = $('.sidebar');
+
+ // good
+ const $sidebar = $('.sidebar');
+
+ // good
+ const $sidebarBtn = $('.sidebar-btn');
+ ```
+
+
+ - [25.2](#jquery--cache) 缓存 jQuery 查询。
+
+ ```javascript
+ // bad
+ function setSidebar() {
+ $('.sidebar').hide();
+
+ // ...stuff...
+
+ $('.sidebar').css({
+ 'background-color': 'pink'
+ });
+ }
+
+ // good
+ function setSidebar() {
+ const $sidebar = $('.sidebar');
+ $sidebar.hide();
+
+ // ...stuff...
+
+ $sidebar.css({
+ 'background-color': 'pink'
+ });
+ }
+ ```
+
+
+ - [25.3](#jquery--queries) 对 DOM 查询使用层叠 `$('.sidebar ul')` 或 父元素 > 子元素 `$('.sidebar > ul')`。
+ [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)
+
+
+ - [25.4](#jquery--find) 对有作用域的 jQuery 对象查询使用 `find`。
+
+ ```javascript
+ // bad
+ $('ul', '.sidebar').hide();
+
+ // bad
+ $('.sidebar').find('ul').hide();
+
+ // good
+ $('.sidebar ul').hide();
+
+ // good
+ $('.sidebar > ul').hide();
+
+ // good
+ $sidebar.find('ul').hide();
+
+ // good (slower)
+ $sidebar.find('ul');
+
+ // good (faster)
+ $($sidebar[0]).find('ul');
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## ECMAScript 5 兼容性
+
+
+ - [26.1](#es5-compat--kangax) 参考 [Kangax](https://twitter.com/kangax/) 的 ES5 [兼容性](http://kangax.github.com/es5-compat-table/).
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## ECMAScript 6(ES 2015+)规范
+
+
+ - [27.1](#es6-styles) 以下是链接到 ES6 的各个特性的列表。
+
+1. [Arrow Functions](#arrow-functions)
+1. [Classes](#classes--constructors)
+1. [Object Shorthand](#es6-object-shorthand)
+1. [Object Concise](#es6-object-concise)
+1. [Object Computed Properties](#es6-computed-properties)
+1. [Template Strings](#es6-template-literals)
+1. [Destructuring](#destructuring)
+1. [Default Parameters](#es6-default-parameters)
+1. [Rest](#es6-rest)
+1. [Array Spreads](#es6-array-spreads)
+1. [Let and Const](#references)
+1. [Iterators and Generators](#iterators-and-generators)
+1. [Modules](#modules)
+
+
+ - [27.2](#tc39-proposals) Do not use [TC39 proposals](https://github.com/tc39/proposals) that have not reached stage 3.
+
+ > Why? [They are not finalized](https://tc39.github.io/process-document/), and they are subject to change or to be withdrawn entirely. We want to use JavaScript, and proposals are not JavaScript yet.
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 测试
+
+
+ - [28.1](#testing--yup) **Yup.**
+
+ ```javascript
+ function foo() {
+ return true;
+ }
+ ```
+
+
+ - [28.2](#testing--for-real) **No, but seriously**:
+
+ - Whichever testing framework you use, you should be writing tests!
+ - Strive to write many small pure functions, and minimize where mutations occur.
+ - Be cautious about stubs and mocks - they can make your tests more brittle.
+ - We primarily use [`mocha`](https://www.npmjs.com/package/mocha) at Airbnb. [`tape`](https://www.npmjs.com/package/tape) is also used occasionally for small, separate modules.
+ - 100% test coverage is a good goal to strive for, even if it's not always practical to reach it.
+ - Whenever you fix a bug, _write a regression test_. A bug fixed without a regression test is almost certainly going to break again in the future.
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 性能
+
+ - [On Layout & Web Performance](https://www.kellegous.com/j/2013/01/26/layout-performance/)
+ - [String vs Array Concat](https://jsperf.com/string-vs-array-concat/2)
+ - [Try/Catch Cost In a Loop](https://jsperf.com/try-catch-in-loop-cost)
+ - [Bang Function](https://jsperf.com/bang-function)
+ - [jQuery Find vs Context, Selector](https://jsperf.com/jquery-find-vs-context-sel/13)
+ - [innerHTML vs textContent for script text](https://jsperf.com/innerhtml-vs-textcontent-for-script-text)
+ - [Long String Concatenation](https://jsperf.com/ya-string-concat)
+ - [Are Javascript functions like `map()`, `reduce()`, and `filter()` optimized for traversing arrays?](https://www.quora.com/JavaScript-programming-language-Are-Javascript-functions-like-map-reduce-and-filter-already-optimized-for-traversing-array/answer/Quildreen-Motta)
+ - Loading...
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 资源
+
+**Learning ES6**
+
+ - [Draft ECMA 2015 (ES6) Spec](https://people.mozilla.org/~jorendorff/es6-draft.html)
+ - [ExploringJS](http://exploringjs.com/)
+ - [ES6 Compatibility Table](https://kangax.github.io/compat-table/es6/)
+ - [Comprehensive Overview of ES6 Features](http://es6-features.org/)
+
+**Read This**
+
+ - [Standard ECMA-262](http://www.ecma-international.org/ecma-262/6.0/index.html)
+ - old [Annotated ECMAScript 5.1](http://es5.github.com/)
+
+**Tools**
+
+ - Code Style Linters
+ + [ESlint](http://eslint.org/) - [Airbnb Style .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc)
+ + [JSHint](http://jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/.jshintrc)
+ + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json)
+
+**Other Style Guides**
+
+ - [Google JavaScript Style Guide](https://google.github.io/styleguide/javascriptguide.xml)
+ - [jQuery Core Style Guidelines](https://contribute.jquery.org/style-guide/js/)
+ - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwaldron/idiomatic.js)
+
+**Other Styles**
+
+ - [Naming this in nested functions](https://gist.github.com/cjohansen/4135065) - Christian Johansen
+ - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen
+ - [Popular JavaScript Coding Conventions on GitHub](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun
+ - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman
+
+**Further Reading**
+
+ - [Understanding JavaScript Closures](https://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll
+ - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer
+ - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz
+ - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban
+ - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock
+
+**Books**
+
+ - [JavaScript: The Good Parts](https://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford
+ - [JavaScript Patterns](https://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov
+ - [Pro JavaScript Design Patterns](https://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz
+ - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](https://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders
+ - [Maintainable JavaScript](https://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas
+ - [JavaScript Web Applications](https://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw
+ - [Pro JavaScript Techniques](https://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig
+ - [Smashing Node.js: JavaScript Everywhere](https://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch
+ - [Secrets of the JavaScript Ninja](https://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault
+ - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg
+ - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
+ - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon
+ - [Third Party JavaScript](https://www.manning.com/books/third-party-javascript) - Ben Vinegar and Anton Kovalyov
+ - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman
+ - [Eloquent JavaScript](http://eloquentjavascript.net/) - Marijn Haverbeke
+ - [You Don't Know JS: ES6 & Beyond](http://shop.oreilly.com/product/0636920033769.do) - Kyle Simpson
+
+**Blogs**
+
+ - [JavaScript Weekly](http://javascriptweekly.com/)
+ - [JavaScript, JavaScript...](https://javascriptweblog.wordpress.com/)
+ - [Bocoup Weblog](https://bocoup.com/weblog)
+ - [Adequately Good](http://www.adequatelygood.com/)
+ - [NCZOnline](https://www.nczonline.net/)
+ - [Perfection Kills](http://perfectionkills.com/)
+ - [Ben Alman](http://benalman.com/)
+ - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/)
+ - [Dustin Diaz](http://dustindiaz.com/)
+ - [nettuts](http://code.tutsplus.com/?s=javascript)
+
+**播客 Podcasts**
+
+ - [JavaScript Air](https://javascriptair.com/)
+ - [JavaScript Jabber](https://devchat.tv/js-jabber/)
+
+
+**[⬆ 返回目录](#table-of-contents)**
+
+## 使用人群
+
+ This is a list of organizations that are using this style guide. Send us a pull request and we'll add you to the list.
+
+ - **4Catalyzer**: [4Catalyzer/javascript](https://github.com/4Catalyzer/javascript)
+ - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript)
+ - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript)
+ - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript)
+ - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript)
+ - **Ascribe**: [ascribe/javascript](https://github.com/ascribe/javascript)
+ - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript)
+ - **Avant**: [avantcredit/javascript](https://github.com/avantcredit/javascript)
+ - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript)
+ - **Bisk**: [bisk/javascript](https://github.com/Bisk/javascript/)
+ - **Blendle**: [blendle/javascript](https://github.com/blendle/javascript)
+ - **Brainshark**: [brainshark/javascript](https://github.com/brainshark/javascript)
+ - **Chartboost**: [ChartBoost/javascript-style-guide](https://github.com/ChartBoost/javascript-style-guide)
+ - **ComparaOnline**: [comparaonline/javascript](https://github.com/comparaonline/javascript-style-guide)
+ - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide)
+ - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript)
+ - **DoSomething**: [DoSomething/eslint-config](https://github.com/DoSomething/eslint-config)
+ - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript)
+ - **Ecosia**: [ecosia/javascript](https://github.com/ecosia/javascript)
+ - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide)
+ - **Evolution Gaming**: [evolution-gaming/javascript](https://github.com/evolution-gaming/javascript)
+ - **EvozonJs**: [evozonjs/javascript](https://github.com/evozonjs/javascript)
+ - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript)
+ - **Expensify** [Expensify/Style-Guide](https://github.com/Expensify/Style-Guide/blob/master/javascript.md)
+ - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide)
+ - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript)
+ - **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript)
+ - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style)
+ - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript)
+ - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript-style-guide)
+ - **Huballin**: [huballin/javascript](https://github.com/huballin/javascript)
+ - **HubSpot**: [HubSpot/javascript](https://github.com/HubSpot/javascript)
+ - **Hyper**: [hyperoslo/javascript-playbook](https://github.com/hyperoslo/javascript-playbook/blob/master/style.md)
+ - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide)
+ - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript)
+ - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions)
+ - **JeopardyBot**: [kesne/jeopardy-bot](https://github.com/kesne/jeopardy-bot/blob/master/STYLEGUIDE.md)
+ - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript)
+ - **KickorStick**: [kickorstick/javascript](https://github.com/kickorstick/javascript)
+ - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/Javascript-style-guide)
+ - **Lonely Planet**: [lonelyplanet/javascript](https://github.com/lonelyplanet/javascript)
+ - **M2GEN**: [M2GEN/javascript](https://github.com/M2GEN/javascript)
+ - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript)
+ - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript)
+ - **MitocGroup**: [MitocGroup/javascript](https://github.com/MitocGroup/javascript)
+ - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript)
+ - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript)
+ - **Muber**: [muber/javascript](https://github.com/muber/javascript)
+ - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript)
+ - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript)
+ - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript)
+ - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript)
+ - **OutBoxSoft**: [OutBoxSoft/javascript](https://github.com/OutBoxSoft/javascript)
+ - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript)
+ - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide)
+ - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript)
+ - **React**: [/facebook/react/blob/master/CONTRIBUTING.md#style-guide](https://github.com/facebook/react/blob/master/CONTRIBUTING.md#style-guide)
+ - **REI**: [reidev/js-style-guide](https://github.com/rei/code-style-guides/blob/master/docs/javascript.md)
+ - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide)
+ - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide)
+ - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript)
+ - **Springload**: [springload/javascript](https://github.com/springload/javascript)
+ - **StratoDem Analytics**: [stratodem/javascript](https://github.com/stratodem/javascript)
+ - **SteelKiwi Development**: [steelkiwi/javascript](https://github.com/steelkiwi/javascript)
+ - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/guide-javascript)
+ - **SysGarage**: [sysgarage/javascript-style-guide](https://github.com/sysgarage/javascript-style-guide)
+ - **Syzygy Warsaw**: [syzygypl/javascript](https://github.com/syzygypl/javascript)
+ - **Target**: [target/javascript](https://github.com/target/javascript)
+ - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript)
+ - **The Nerdery**: [thenerdery/javascript-standards](https://github.com/thenerdery/javascript-standards)
+ - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript)
+ - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide)
+ - **WeBox Studio**: [weboxstudio/javascript](https://github.com/weboxstudio/javascript)
+ - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript)
+ - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript)
+ - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript)
+
+**[⬆ 返回目录](#table-of-contents)**
+
+## 翻译
+
+ This style guide is also available in other languages:
+
+ -  **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide)
+ -  **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript)
+ -  **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide)
+ -  **Chinese (Simplified)**: [sivan/javascript-style-guide](https://github.com/sivan/javascript-style-guide)
+ -  **Chinese (Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript)
+ -  **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide)
+ -  **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide)
+ -  **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide)
+ -  **Japanese**: [mitsuruog/javascript-style-guide](https://github.com/mitsuruog/javascript-style-guide)
+ -  **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide)
+ -  **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript)
+ -  **Russian**: [uprock/javascript](https://github.com/uprock/javascript)
+ -  **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide)
+ -  **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide)
+ -  **Vietnam**: [giangpii/javascript-style-guide](https://github.com/giangpii/javascript-style-guide)
+
+
+## JavaScript 编码规范说明
+
+ - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide)
+
+
+## 一起来讨论 JavaScript
+
+ - Find us on [gitter](https://gitter.im/airbnb/javascript).
+
+
+## 贡献者 Contributors
+
+ - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors)
+
+
+## 许可 License
+
+(The MIT License)
+
+Copyright (c) 2014-2017 Airbnb
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 修正案 Amendments
+
+We encourage you to fork this guide and change the rules to fit your team's style guide. Below, you may list some amendments to the style guide. This allows you to periodically update your style guide without having to deal with merge conflicts.
+
+# };
diff --git a/docs/es6_zh-cn_v3.md b/docs/es6_zh-cn_v3.md
new file mode 100644
index 0000000000..36f57fbe7c
--- /dev/null
+++ b/docs/es6_zh-cn_v3.md
@@ -0,0 +1,3607 @@
+[](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+# Airbnb JavaScript Style Guide() {
+
+*A mostly reasonable approach to JavaScript——用更合理的方式写 JavaScript*
+
+翻译自 [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) 。
+
+NOTE: Airbnb 规则非常超前,在编译时,ES6无法完全支持,如对象扩展运算符是 ES2017 引入的,此时,需要使用 [stage-0](http://www.cnblogs.com/chris-oil/p/5717544.html) 等设置来支持,另外使用规范时注意以下部分略有调整。
+
+```
+// 使用右键 Run Code 时,有些语法是不支持的,这是因为 node 的环境还不支持
+// 此时可以使用 babel-node 加载 babel-preset-stage-0 来获得对新语法的支持
+
+"code-runner.executorMap": {
+ "javascript": "babel-node --presets stage-0"
+}
+
+NOTE: babel-preset-stage-0 必须要安装到项目目录才可以被引用,安装全局是不行的。
+```
+
+- 尾逗号单行不要有,多行必须有。修改规则 `comma-dangle: ['error', 'never']` 中 never 改为 always-multiline。
+- 行尾不要分号。调整后,代码更干净、整洁,但要注意 (, [, + , -, or ` 开头的语句,可能在“自动分号插入”机制(ASI)下会有问题。
+ 为什么? 参看[是否要分号的讨论](https://github.com/feross/standard/blob/master/RULES.md#helpful-reading)
+- 本文档有大量对 ES6 新特性规则要求,此外的书写要求兼容 [ES5 代码规范](http://standardjs.com/rules.html)。
+- 注意以下情况:
+ - 不要行尾空格
+ - 文档底部保留一个空行
+ - 空白行不要有空白字符
+ - 空白行使用一次最多连续两行
+ - 禁止未使用过的变量,但设置为不检查参数 "no-unused-vars": ["error", { "args": "none" }],
+ - 箭头函数的参数使用圆括号,但参数只有一个时,可以省略圆括号,但若函数体在指令块中则必须写圆括号
+ - webpack2 打包限制,可以在js文件中混用require和export,但是不能混用import和module.exports。
+
+该文档保留了部分还属于 ES5 范畴的注意内容,由 old: ES5 标记。
+
+相关链接:
+
+- [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript)
+- [ES6/ES2015 版](https://github.com/webcoding/javascript-style-guide/tree/master/docs/es6_zh-cn_v3.md)
+- [ES5 版](https://github.com/webcoding/javascript-style-guide/tree/master/docs/es5_zh-cn_v3.md)
+- [React/JSX 版](https://github.com/webcoding/javascript-style-guide/tree/master/react/zh-cn.md)
+- [VueJS 版](https://github.com/jackbarham/vuejs-style-guide)
+
+扩展使用 eslint-plugin-html eslint-plugin-vue
+
+## Usage
+
+参见[config-eslint](./config-eslint.md)
+
+NOTE: 使用规范最好的方式,就是配置好,直接用,然后各种问题就出来了
+
+[](https://www.npmjs.com/package/eslint-config-airbnb)
+[](https://www.npmjs.com/package/eslint-config-airbnb-base)
+[](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+Other Style Guides
+
+ - [ES5 (Deprecated)](https://github.com/airbnb/javascript/tree/es5-deprecated/es5)
+ - [React](react/)
+ - [CSS-in-JavaScript](css-in-javascript/)
+ - [CSS & Sass](https://github.com/airbnb/css)
+ - [CSS & Sass 中文版](https://github.com/webcoding/css-style-guide)
+ - [Ruby](https://github.com/airbnb/ruby)
+
+
+
+## 目录
+
+ 1. [类型](#types)
+ 1. [引用](#references)
+ 1. [对象](#objects)
+ 1. [数组](#arrays)
+ 1. [解构](#destructuring)
+ 1. [字符串](#strings)
+ 1. [函数](#functions)
+ 1. [箭头函数](#arrow-functions)
+ 1. [类 & 构造函数](#classes--constructors)
+ 1. [模块](#modules)
+ 1. [Iterators and Generators](#iterators-and-generators)
+ 1. [属性](#properties)
+ 1. [变量](#variables)
+ 1. [提升](#hoisting)
+ 1. [比较运算符 & 等号](#comparison-operators--equality)
+ 1. [代码块](#blocks)
+ 1. [注释](#comments)
+ 1. [空白](#whitespace)
+ 1. [逗号](#commas)
+ 1. [分号](#semicolons)
+ 1. [类型转换](#type-casting--coercion)
+ 1. [命名规则](#naming-conventions)
+ 1. [存取器](#accessors)
+ 1. [事件](#events)
+ 1. [jQuery](#jquery)
+ 1. [ECMAScript 5 兼容性](#ecmascript-5-compatibility)
+ 1. [ECMAScript 6+ (ES 2015+) 编码规范](#ecmascript-6-styles)
+ 1. [测试](#testing)
+ 1. [性能](#performance)
+ 1. [资源](#resources)
+ 1. [使用人群](#in-the-wild)
+ 1. [翻译](#translation)
+ 1. [JavaScript 编码规范说明](#the-javascript-style-guide-guide)
+ 1. [一起来讨论 JavaScript](#chat-with-us-about-javascript)
+ 1. [Contributors](#contributors)
+ 1. [License](#license)
+
+
+
+## 类型
+
+
+ - [1.1](#types--primitives) **基本类型**: 直接存取基本类型。
+
+ + `string` 字符串
+ + `number` 数值
+ + `boolean` 布尔类型
+ + `null`
+ + `undefined`
+
+ ```javascript
+ const foo = 1;
+ let bar = foo;
+
+ bar = 9;
+
+ console.log(foo, bar); // => 1, 9
+ ```
+
+
+ - [1.2](#types--complex) **复杂类型**: 通过引用的方式存取复杂类型。
+
+ + `object` 对象
+ + `array` 数组
+ + `function` 函数
+
+ ```javascript
+ const foo = [1, 2];
+ const bar = foo;
+
+ bar[0] = 9;
+
+ console.log(foo[0], bar[0]); // => 9, 9
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 引用
+
+
+ - [2.1](#references--prefer-const) 对所有的引用使用 `const`,不要使用 `var`。
+ eslint: [`prefer-const`](http://eslint.org/docs/rules/prefer-const.html), [`no-const-assign`](http://eslint.org/docs/rules/no-const-assign.html)
+
+ > 为什么? 这能确保你无法对引用重新赋值,也不会导致出现 bug 或难以理解。
+
+ ```javascript
+ // bad
+ var a = 1;
+ var b = 2;
+
+ // good
+ const a = 1;
+ const b = 2;
+ ```
+
+
+ - [2.2](#references--disallow-var) 如果你一定需要可变动的引用,使用 `let` 代替 `var`。
+ eslint: [`no-var`](http://eslint.org/docs/rules/no-var.html)
+ jscs: [`disallowVar`](http://jscs.info/rule/disallowVar)
+
+ > 为什么? 因为 `let` 是块级作用域,而 `var` 是函数作用域。
+
+ ```javascript
+ // bad
+ var count = 1;
+ if (true) {
+ count += 1;
+ }
+
+ // good, use the let.
+ let count = 1;
+ if (true) {
+ count += 1;
+ }
+ ```
+
+
+ - [2.3](#references--block-scope) 注意 `let` 和 `const` 都是块级作用域。
+
+ ```javascript
+ // const 和 let 只存在于它们被定义的区块内。
+ {
+ let a = 1;
+ const b = 1;
+ }
+ console.log(a); // ReferenceError
+ console.log(b); // ReferenceError
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 对象
+
+
+ - [3.1](#objects--no-new) 使用字面值创建对象。
+ eslint: [`no-new-object`](http://eslint.org/docs/rules/no-new-object.html)
+
+ ```javascript
+ // bad
+ const item = new Object();
+
+ // good
+ const item = {};
+ ```
+
+
+ - [3.2](#es6-computed-properties) 创建有动态属性名的对象时,使用可被计算的属性名称。
+
+ > 为什么? 因为这样可以让你在一个地方定义所有的对象属性。
+
+ ```javascript
+ function getKey(k) {
+ return `a key named ${k}`;
+ }
+
+ // bad
+ const obj = {
+ id: 5,
+ name: 'San Francisco',
+ };
+ obj[getKey('enabled')] = true;
+
+ // good
+ const obj = {
+ id: 5,
+ name: 'San Francisco',
+ [getKey('enabled')]: true,
+ };
+ ```
+
+
+ - [3.3](#es6-object-shorthand) 使用对象方法的简写。
+ eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html)
+ jscs: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals)
+
+ ```javascript
+ // bad
+ const atom = {
+ value: 1,
+
+ addValue: function (value) {
+ return atom.value + value;
+ },
+ };
+
+ // good
+ const atom = {
+ value: 1,
+
+ addValue(value) {
+ return atom.value + value;
+ },
+ };
+ ```
+
+
+ - [3.4](#es6-object-concise) 使用对象属性值的简写。
+ eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html)
+ jscs: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals)
+
+ > 为什么? 因为这样更短更有描述性。
+
+ ```javascript
+ const lukeSkywalker = 'Luke Skywalker';
+
+ // bad
+ const obj = {
+ lukeSkywalker: lukeSkywalker,
+ };
+
+ // good
+ const obj = {
+ lukeSkywalker,
+ };
+ ```
+
+
+ - [3.5](#objects--grouped-shorthand) 在对象属性声明前把简写的属性分组。
+
+ > 为什么? 因为这样能清楚地看出哪些属性使用了简写。
+
+ ```javascript
+ const anakinSkywalker = 'Anakin Skywalker';
+ const lukeSkywalker = 'Luke Skywalker';
+
+ // bad
+ const obj = {
+ episodeOne: 1,
+ twoJediWalkIntoACantina: 2,
+ lukeSkywalker,
+ episodeThree: 3,
+ mayTheFourth: 4,
+ anakinSkywalker,
+ };
+
+ // good
+ const obj = {
+ lukeSkywalker,
+ anakinSkywalker,
+ episodeOne: 1,
+ twoJediWalkIntoACantina: 2,
+ episodeThree: 3,
+ mayTheFourth: 4,
+ };
+ ```
+
+
+ - [3.6](#objects--quoted-props) 只用引号包裹属性名称是无效标识符的那些。
+ eslint: [`quote-props`](http://eslint.org/docs/rules/quote-props.html)
+ jscs: [`disallowQuotedKeysInObjects`](http://jscs.info/rule/disallowQuotedKeysInObjects)
+
+ > 为什么? 通常我认为这样更容易阅读,这样可以使用语法高亮并且许多 js 引擎也更容易优化代码。
+
+ ```javascript
+ // bad
+ const bad = {
+ 'foo': 3,
+ 'bar': 4,
+ 'data-blah': 5,
+ };
+
+ // good
+ const good = {
+ foo: 3,
+ bar: 4,
+ 'data-blah': 5,
+ };
+ ```
+
+
+ - [3.7](#objects--prototype-builtins) 不要直接调用 `Object.prototype` 的方法,如 `hasOwnProperty`, `propertyIsEnumerable`, and `isPrototypeOf`
+
+ > 为什么? 这些方法可能会有问题,比如 `{ hasOwnProperty: false }` 的情况 或者 可能是 null object (`Object.create(null)`)。
+
+ ```javascript
+ // bad
+ console.log(object.hasOwnProperty(key));
+
+ // good
+ console.log(Object.prototype.hasOwnProperty.call(object, key));
+
+ // best
+ const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
+ /* or */
+ import has from 'has';
+ // ...
+ console.log(has.call(object, key));
+ ```
+
+
+ - [3.8](#objects--rest-spread) 浅拷贝使用对象扩展符(rest operator)更好,相对于方法 [`Object.assign`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) 而言。
+
+ NOTE: Object.assign 实行的是浅拷贝,而不是深拷贝。其拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)。
+
+ 扩展运算符可以深拷贝么?可以。
+
+ ```javascript
+ // very bad
+ const original = { a: 1, b: 2 };
+ const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
+ delete copy.a; // so does this
+
+ // bad
+ const original = { a: 1, b: 2 };
+ const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
+
+ // good
+ const original = { a: 1, b: 2 };
+ const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
+
+ const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
+ ```
+
+ - old: ES5 [3.11](#3.11) 如果你的代码在浏览器环境下执行,不要使用 [保留字](http://es5.github.io/#x7.6.1) 作为键值。这样的话在 IE8 不会运行。 [更多信息](https://github.com/airbnb/javascript/issues/61)。 但在 ES6 模块和服务器端中使用没有问题。
+
+ NOTE: 这是 ES5 的要求,在浏览器端(目前情况下)仍要注意遵守此要求。
+
+ ```javascript
+ // bad
+ const superman = {
+ default: { clark: 'kent' },
+ private: true,
+ };
+
+ // good
+ const superman = {
+ defaults: { clark: 'kent' },
+ hidden: true,
+ };
+ ```
+
+ - old: ES5 [3.12](#3.12) 使用同义词替换需要使用的保留字。
+
+ ```javascript
+ // bad
+ const superman = {
+ class: 'alien',
+ };
+
+ // bad
+ const superman = {
+ klass: 'alien',
+ };
+
+ // good
+ const superman = {
+ type: 'alien',
+ };
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 数组
+
+
+ - [4.1](#arrays--literals) 使用字面值创建数组。
+ eslint: [`no-array-constructor`](http://eslint.org/docs/rules/no-array-constructor.html)
+
+ ```javascript
+ // bad
+ const items = new Array();
+
+ // good
+ const items = [];
+ ```
+
+
+ - [4.2](#arrays--push) 向数组添加元素时使用 [Array#push](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/push) 替代直接赋值。
+
+ ```javascript
+ const someStack = [];
+
+ // bad
+ someStack[someStack.length] = 'abracadabra';
+
+ // good
+ someStack.push('abracadabra');
+ ```
+
+
+ - [4.3](#es6-array-spreads) 使用拓展运算符 `...` 复制数组。
+
+ ```javascript
+ // bad
+ const len = items.length;
+ const itemsCopy = [];
+ let i;
+
+ for (i = 0; i < len; i += 1) {
+ itemsCopy[i] = items[i];
+ }
+
+ // good
+ const itemsCopy = [...items];
+
+ // old: ES5
+ // 当你需要拷贝数组时使用slice. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7)
+ itemsCopy = items.slice();
+ ```
+
+
+ - [4.4](#arrays--from) 使用 [Array.from](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from) 把一个类数组对象转换成数组。
+
+ ```javascript
+ const foo = document.querySelectorAll('.foo');
+ const nodes = Array.from(foo);
+
+ // old: ES5
+ // 使用slice将类数组的对象转成数组.
+ function trigger() {
+ var args = Array.prototype.slice.call(arguments);
+ ...
+ }
+ ```
+
+
+ - [4.5](#arrays--callback-return) 在回调函数中使用 return 语句。如果函数体只由一个单独的语句组成,可以省略 return 关键字 [8.2](#8.2).
+ eslint: [`array-callback-return`](http://eslint.org/docs/rules/array-callback-return)
+
+ ```javascript
+ // good
+ [1, 2, 3].map((x) => {
+ const y = x + 1;
+ return x * y;
+ });
+
+ // good
+ [1, 2, 3].map(x => x + 1);
+
+ // bad
+ const flat = {};
+ [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
+ const flatten = memo.concat(item);
+ flat[index] = flatten;
+ });
+
+ // good
+ const flat = {};
+ [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
+ const flatten = memo.concat(item);
+ flat[index] = flatten;
+ return flatten;
+ });
+
+ // bad
+ inbox.filter((msg) => {
+ const { subject, author } = msg;
+ if (subject === 'Mockingbird') {
+ return author === 'Harper Lee';
+ } else {
+ return false;
+ }
+ });
+
+ // good
+ inbox.filter((msg) => {
+ const { subject, author } = msg;
+ if (subject === 'Mockingbird') {
+ return author === 'Harper Lee';
+ }
+
+ return false;
+ });
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 解构
+
+
+ - [5.1](#destructuring--object) 使用解构存取和使用多属性对象。
+ jscs: [`requireObjectDestructuring`](http://jscs.info/rule/requireObjectDestructuring)
+
+ > 为什么? 因为解构能减少临时引用属性。
+
+ ```javascript
+ // bad
+ function getFullName(user) {
+ const firstName = user.firstName;
+ const lastName = user.lastName;
+
+ return `${firstName} ${lastName}`;
+ }
+
+ // good
+ function getFullName(user) {
+ const { firstName, lastName } = user;
+ return `${firstName} ${lastName}`;
+ }
+
+ // best
+ function getFullName({ firstName, lastName }) {
+ return `${firstName} ${lastName}`;
+ }
+ ```
+
+
+ - [5.2](#destructuring--array) 对数组使用解构赋值。
+ jscs: [`requireArrayDestructuring`](http://jscs.info/rule/requireArrayDestructuring)
+
+ ```javascript
+ const arr = [1, 2, 3, 4];
+
+ // bad
+ const first = arr[0];
+ const second = arr[1];
+
+ // good
+ const [first, second] = arr;
+ ```
+
+
+ - [5.3](#destructuring--object-over-array) 需要回传多个值时,使用对象解构,而不是数组解构。
+ jscs: [`disallowArrayDestructuringReturn`](http://jscs.info/rule/disallowArrayDestructuringReturn)
+
+ > 为什么? 增加属性或者改变排序不会改变调用时的位置。
+
+ ```javascript
+ // bad
+ function processInput(input) {
+ // then a miracle occurs
+ return [left, right, top, bottom];
+ }
+
+ // 调用时需要考虑回调数据的顺序。
+ const [left, __, top] = processInput(input);
+
+ // good
+ function processInput(input) {
+ // then a miracle occurs
+ return { left, right, top, bottom };
+ }
+
+ // 调用时只选择需要的数据
+ const { left, top } = processInput(input);
+ ```
+
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## Strings
+
+
+ - [6.1](#strings--quotes) 字符串使用单引号 `''` 。
+ eslint: [`quotes`](http://eslint.org/docs/rules/quotes.html)
+ jscs: [`validateQuoteMarks`](http://jscs.info/rule/validateQuoteMarks)
+
+ ```javascript
+ // bad
+ const name = "Capt. Janeway";
+
+ // bad - template literals should contain interpolation or newlines
+ const name = `Capt. Janeway`;
+
+ // good
+ const name = 'Capt. Janeway';
+ ```
+
+
+ - [6.2](#strings--line-length) 字符串超过 100 个字节应该使用字符串连接号换行。此处可以更多个字符200或300,目前编辑界面越来越大了
+
+ > 为什么? 切断长字符串,可以更好编码和搜索。
+
+ 注:过度使用字串连接符号可能会对性能造成影响。[jsPerf](http://jsperf.com/ya-string-concat) 和 [讨论](https://github.com/airbnb/javascript/issues/40).
+
+ ```javascript
+ // bad
+ 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.';
+
+ // bad
+ 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.';
+
+ // good
+ 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.';
+ ```
+
+
+ - [6.3](#es6-template-literals) 程序化生成字符串时,使用模板字符串代替字符串连接。
+ eslint: [`prefer-template`](http://eslint.org/docs/rules/prefer-template.html) [`template-curly-spacing`](http://eslint.org/docs/rules/template-curly-spacing)
+ jscs: [`requireTemplateStrings`](http://jscs.info/rule/requireTemplateStrings)
+
+ > 为什么? 模板字符串插值更为简洁,更具可读性。
+
+ ```javascript
+ // bad
+ function sayHi(name) {
+ return 'How are you, ' + name + '?';
+ }
+
+ // bad
+ function sayHi(name) {
+ return ['How are you, ', name, '?'].join();
+ }
+
+ // bad
+ function sayHi(name) {
+ return `How are you, ${ name }?`;
+ }
+
+ // good
+ function sayHi(name) {
+ return `How are you, ${name}?`;
+ }
+ ```
+
+
+ - [6.4](#strings--eval) 在字符串中永不使用 `eval()`, 它会导致很多漏洞。
+
+
+ - [6.5](#strings--escaping) 字符串中不要使用不必要的转义。
+ eslint: [`no-useless-escape`](http://eslint.org/docs/rules/no-useless-escape)
+
+ > 为什么? 反斜杠会降低可读性,应该在必要时才去使用它。
+
+ ```javascript
+ // bad
+ const foo = '\'this\' \i\s \"quoted\"';
+
+ // good
+ const foo = '\'this\' is "quoted"';
+ const foo = `my name is '${name}'`;
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 函数
+
+
+ - [7.1](#functions--declarations) 使用函数表达式,而不是函数声明。
+ eslint: [`func-style`](http://eslint.org/docs/rules/func-style)
+ jscs: [`requireFunctionDeclarations`](http://jscs.info/rule/requireFunctionDeclarations)
+
+ > 为什么? 函数声明会把整个函数提升(hoisted),这导致非常容易在定义以前就被引用,这会降低可读性以及维护性(而函数表达式只会把函数的引用变量名提升)。如果发现一个函数定义非常大或复杂,会干扰其他逻辑的理解,此时也许是时候把它提取成独立模块了。
+
+ > 另外不要忘记给匿名表达式命名,匿名函数会使错误堆栈中跟踪问题更加困难。
+
+ > 函数提升规则,使得[箭头函数](#arrow-functions)可以取代函数表达式。
+
+ ```javascript
+ // bad
+ function foo() {
+ // ...
+ }
+
+ // bad
+ const foo = function () {
+ // ...
+ };
+
+ // good
+ const foo = function bar() {
+ // ...
+ };
+ ```
+
+
+ - [7.2](#functions--iife) 用括号包裹 立即调用函数表达式(IIFE)。
+ eslint: [`wrap-iife`](http://eslint.org/docs/rules/wrap-iife.html)
+ jscs: [`requireParenthesesAroundIIFE`](http://jscs.info/rule/requireParenthesesAroundIIFE)
+
+ > 为什么? 立即调用表达式(IIFE) 要使用圆括号包裹成一个独立的单元,这样表达更清晰。NOTE: 在模块的世界,你已经不再需要 IIFE 了。
+
+ ```javascript
+ // 立即调用的函数表达式 (IIFE)
+ // 可使用箭头函数
+ // (() => {
+ (function () {
+ console.log('Welcome to the Internet. Please follow me.');
+ }());
+ ```
+
+
+ - [7.3](#functions--in-blocks) 永远不要在一个非函数代码块(`if`、`while` 等)中声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但它们的解析表现不一致。
+ eslint: [`no-loop-func`](http://eslint.org/docs/rules/no-loop-func.html)
+
+
+ - [7.4](#functions--note-on-blocks) NOTE: ECMA-262 把 `block` 定义为一组语句。函数声明不是语句。[阅读 ECMA-262 关于这个问题的说明](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97)。
+
+ ```javascript
+ // bad
+ if (currentUser) {
+ function test() {
+ console.log('Nope.');
+ }
+ }
+
+ // good
+ let test;
+ if (currentUser) {
+ test = () => {
+ console.log('Yup.');
+ };
+ }
+ ```
+
+
+ - [7.5](#functions--arguments-shadow) 永远不要把参数命名为 `arguments`。这将取代原来函数作用域内的 `arguments` 对象。
+
+ ```javascript
+ // bad
+ function foo(name, options, arguments) {
+ // ...
+ }
+
+ // good
+ function foo(name, options, args) {
+ // ...
+ }
+ ```
+
+
+ - [7.6](#es6-rest) 不要使用 `arguments`。可以选择 rest 语法 `...` 替代。
+ eslint: [`prefer-rest-params`](http://eslint.org/docs/rules/prefer-rest-params)
+
+ > 为什么? 使用 `...` 能明确你要传入的参数。另外 rest 参数是一个真正的数组,而 `arguments` 是一个类数组。
+
+ ```javascript
+ // bad
+ function concatenateAll() {
+ const args = Array.prototype.slice.call(arguments);
+ return args.join('');
+ }
+
+ // good
+ function concatenateAll(...args) {
+ return args.join('');
+ }
+ ```
+
+
+ - [7.7](#es6-default-parameters) 直接给函数的参数指定默认值,不要使用一个变化的函数参数。
+
+ ```javascript
+ // really bad
+ function handleThings(opts) {
+ // 不!我们不应该改变函数参数。
+ // 更加糟糕: 如果参数 opts 是 false 的话,它就会被设定为一个对象。
+ // 但这样的写法会造成一些 Bugs。
+ //(译注:例如当 opts 被赋值为空字符串,opts 仍然会被下一行代码设定为一个空对象。)
+ opts = opts || {};
+ // ...
+ }
+
+ // still bad
+ function handleThings(opts) {
+ if (opts === void 0) {
+ opts = {};
+ }
+ // ...
+ }
+
+ // good
+ function handleThings(opts = {}) {
+ // ? 对比以上写法核心区别是啥?
+ // ...
+ }
+ ```
+
+
+ - [7.8](#functions--default-side-effects) 函数参数设置默认值,要避免副作用。
+
+ > 为什么? 因为这样会让人感到很困惑。
+
+ ```javascript
+ var b = 1;
+ // bad
+ function count(a = b++) {
+ console.log(a);
+ }
+ count(); // 1
+ count(); // 2
+ count(3); // 3
+ count(); // 3
+ ```
+
+
+ - [7.9](#functions--defaults-last) 总是把默认参数最后。
+
+ ```javascript
+ // bad
+ function handleThings(opts = {}, name) {
+ // ...
+ }
+
+ // good
+ function handleThings(name, opts = {}) {
+ // ...
+ }
+ ```
+
+
+ - [7.10](#functions--constructor) 永远不要使用构造函数创建新函数。
+ eslint: [`no-new-func`](http://eslint.org/docs/rules/no-new-func)
+
+ > 为什么? 以这种方式创建一个函数,类似 eval(),会导致很多漏洞。
+
+ ```javascript
+ // bad
+ var add = new Function('a', 'b', 'return a + b');
+
+ // still bad
+ var subtract = Function('a', 'b', 'return a - b');
+ ```
+
+
+ - [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)
+
+ > 为什么? 一致性好,当添加或移除名称时,不必添加或移除空间。
+
+ ```javascript
+ // bad
+ const f = function(){};
+ const g = function (){};
+ const h = function() {};
+
+ // good
+ const x = function () {};
+ const y = function a() {};
+ ```
+
+
+ - [7.12](#functions--mutate-params) 不要使用变异参数。
+ eslint: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign.html)
+
+ > 为什么? 操纵传入的参数,在原调用者上可能会导致不必要的变量副作用。
+
+ ```javascript
+ // bad
+ function f1(obj) {
+ obj.key = 1;
+ }
+
+ // good
+ function f2(obj) {
+ const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
+ }
+ ```
+
+
+ - [7.13](#functions--reassign-params) 不要给形参重新赋值。
+ eslint: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign.html)
+
+ > 为什么? 这样做可能会导致意外行为,特别是操作 `arguments` 参数。这也会导致优化问题,特别是使用 V8 解析器.
+
+ ```javascript
+ // bad
+ function f1(a) {
+ a = 1;
+ // ...
+ }
+
+ function f2(a) {
+ if (!a) { a = 1; }
+ // ...
+ }
+
+ // good
+ function f3(a) {
+ const b = a || 1;
+ // ...
+ }
+
+ function f4(a = 1) {
+ // ...
+ }
+ ```
+
+
+ - [7.14](#functions--spread-vs-apply) 使用拓展操作符 `...` 调用可变参函数。
+ eslint: [`prefer-spread`](http://eslint.org/docs/rules/prefer-spread)
+
+ > 为什么? 更简洁、并且也不用提供上下文作用域,而使用 `new` 和 `apply` 也没这个容易。
+
+ ```javascript
+ // bad
+ const x = [1, 2, 3, 4, 5];
+ console.log.apply(console, x);
+
+ // good
+ const x = [1, 2, 3, 4, 5];
+ console.log(...x);
+
+ // bad
+ new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));
+
+ // good
+ new Date(...[2016, 8, 5]);
+ ```
+
+
+ - [7.15](#functions--signature-invocation-indentation) 函数声明或调用参数写成多行时,书写规则: 每项独占一行,保持缩进,且后面跟个逗号。
+
+ ```javascript
+ // bad
+ function foo(bar,
+ baz,
+ quux) {
+ // ...
+ }
+
+ // good
+ function foo(
+ bar,
+ baz,
+ quux,
+ ) {
+ // ...
+ }
+
+ // bad
+ console.log(foo,
+ bar,
+ baz);
+
+ // good
+ console.log(
+ foo,
+ bar,
+ baz,
+ );
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 箭头函数
+
+
+ - [8.1](#arrows--use-them) 当你必须使用函数表达式(或传递一个匿名函数)时,使用箭头函数符号。
+ eslint: [`prefer-arrow-callback`](http://eslint.org/docs/rules/prefer-arrow-callback.html), [`arrow-spacing`](http://eslint.org/docs/rules/arrow-spacing.html)
+ jscs: [`requireArrowFunctions`](http://jscs.info/rule/requireArrowFunctions)
+
+ > 为什么? 因为箭头函数会创建一个你通常最想要的 `this` 执行环境,而且语法也更简洁(译注:参考 [Arrow functions - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) 和 [ES6 arrow functions, syntax and lexical scoping](http://toddmotto.com/es6-arrow-functions-syntaxes-and-lexical-scoping/)),通常情况下都能满足你的需求,而且这样的写法更为简洁。
+
+ > 为什么不?如果你有一个相当复杂的函数,你或许可以把逻辑部分转移到一个函数声明上。
+
+ ```javascript
+ // bad
+ [1, 2, 3].map(function (x) {
+ const y = x + 1;
+ return x * y;
+ });
+
+ // good
+ [1, 2, 3].map((x) => {
+ const y = x + 1;
+ return x * y;
+ });
+ ```
+
+
+ - [8.2](#arrows--implicit-return) 如果一个函数适合用一行写出并且只有一个参数,那就把花括号、圆括号和 `return` 都省略掉。如果不是,那就不要省略。
+
+ > 为什么? 这是语法糖。在链式调用中可读性很高。
+
+ > 为什么不?当你打算回传一个对象的时候。
+
+ ```javascript
+ // bad
+ [1, 2, 3].map(number => {
+ const nextNumber = number + 1;
+ `A string containing the ${nextNumber}.`;
+ });
+
+ // good
+ [1, 2, 3].map(number => `A string containing the ${number}.`);
+
+ // good
+ [1, 2, 3].map((number) => {
+ const nextNumber = number + 1;
+ return `A string containing the ${nextNumber}.`;
+ });
+
+ // good
+ [1, 2, 3].map((number, index) => ({
+ [index]: number,
+ }));
+ ```
+
+
+ - [8.3](#arrows--paren-wrap) 如果表达式有多行,使用圆括号包裹,提高可读性。
+
+ > 为什么? 这样能更清楚的看到开始和结束位置。
+
+ ```javascript
+ // bad
+ ['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call(
+ httpMagicObjectWithAVeryLongName,
+ httpMethod,
+ )
+ );
+
+ // good
+ ['get', 'post', 'put'].map(httpMethod => (
+ Object.prototype.hasOwnProperty.call(
+ httpMagicObjectWithAVeryLongName,
+ httpMethod,
+ )
+ ));
+ ```
+
+
+ - [8.4](#arrows--one-arg-parens) 如果函数需要单一的参数那就省略掉圆括号,否则总是用圆括号包裹参数,这样更清晰。NOTE: 总是使用圆括号也是可以接受的,但要设置在 ESLint 中用["always"](http://eslint.org/docs/rules/arrow-parens#always),jscs 中用[`disallowParenthesesAroundArrowParam`](http://jscs.info/rule/disallowParenthesesAroundArrowParam)
+ eslint: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html)
+ jscs: [`disallowParenthesesAroundArrowParam`](http://jscs.info/rule/disallowParenthesesAroundArrowParam)
+
+ > 为什么? 更少的视觉干扰
+
+ NOTE: 箭头函数的参数使用圆括号,但参数只有一个时,可以省略圆括号,但若函数体在指令块中则必须写圆括号。配置为 "arrow-parens": ["error", "as-needed", { "requireForBlockBody": true }]
+
+ ```javascript
+ // bad
+ [1, 2, 3].map((x) => x * x);
+
+ // good
+ [1, 2, 3].map(x => x * x);
+
+ // good
+ [1, 2, 3].reduce((total, n) => {
+ return total + n;
+ }, 0);
+
+ // good
+ [1, 2, 3].map(number => (
+ `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
+ ));
+
+ // bad
+ [1, 2, 3].map(x => {
+ const y = x + 1;
+ return x * y;
+ });
+
+ // good
+ [1, 2, 3].map((x) => {
+ const y = x + 1;
+ return x * y;
+ });
+
+ // bad
+ export default context => {
+ // ...
+ return app
+ }
+ ```
+
+
+ - [8.5](#arrows--confusing) 避免使用比较操作符 (`<=`, `>=`),会混淆 箭头函数语法 (`=>`)
+ eslint: [`no-confusing-arrow`](http://eslint.org/docs/rules/no-confusing-arrow)
+
+ ```javascript
+ // bad
+ const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize;
+
+ // bad
+ const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize;
+
+ // good
+ const itemHeight = item => (item.height > 256 ? item.largeSize : item.smallSize);
+
+ // good
+ const itemHeight = (item) => {
+ const { height, largeSize, smallSize } = item;
+ return height > 256 ? largeSize : smallSize;
+ };
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 类 & 构造器
+
+
+ - [9.1](#constructors--use-class) 总是使用 `class`。避免直接操作 `prototype` 。
+
+ > 为什么? 因为 `class` 语法更为简洁更易读。
+
+ ```javascript
+ // bad
+ function Queue(contents = []) {
+ this.queue = [...contents];
+ }
+ Queue.prototype.pop = function () {
+ const value = this.queue[0];
+ this.queue.splice(0, 1);
+ return value;
+ };
+
+
+ // good
+ class Queue {
+ constructor(contents = []) {
+ this.queue = [...contents];
+ }
+ pop() {
+ const value = this.queue[0];
+ this.queue.splice(0, 1);
+ return value;
+ }
+ }
+ ```
+
+
+ - [9.2](#constructors--extends) 使用 `extends` 继承。
+
+ > 为什么? 因为 `extends` 是一个内建的原型继承方法并且不会破坏 `instanceof`。
+
+ ```javascript
+ // bad
+ const inherits = require('inherits');
+ function PeekableQueue(contents) {
+ Queue.apply(this, contents);
+ }
+ inherits(PeekableQueue, Queue);
+ PeekableQueue.prototype.peek = function () {
+ return this.queue[0];
+ };
+
+ // good
+ class PeekableQueue extends Queue {
+ peek() {
+ return this.queue[0];
+ }
+ }
+ ```
+
+
+ - [9.3](#constructors--chaining) 方法可以返回 `this` 以便于链式调用。
+
+ ```javascript
+ // bad
+ Jedi.prototype.jump = function () {
+ this.jumping = true;
+ return true;
+ };
+
+ Jedi.prototype.setHeight = function (height) {
+ this.height = height;
+ };
+
+ const luke = new Jedi();
+ luke.jump(); // => true
+ luke.setHeight(20); // => undefined
+
+ // good
+ class Jedi {
+ jump() {
+ this.jumping = true;
+ return this;
+ }
+
+ setHeight(height) {
+ this.height = height;
+ return this;
+ }
+ }
+
+ const luke = new Jedi();
+
+ luke.jump()
+ .setHeight(20);
+ ```
+
+
+
+ - [9.4](#constructors--tostring) 可以自定义 `toString()` 方法,但要确保它能正常运行并且不会引起副作用。
+
+ ```javascript
+ class Jedi {
+ constructor(options = {}) {
+ this.name = options.name || 'no name';
+ }
+
+ getName() {
+ return this.name;
+ }
+
+ toString() {
+ return `Jedi - ${this.getName()}`;
+ }
+ }
+ ```
+
+
+ - [9.5](#constructors--no-useless) 类有默认构造函数,书写一个空的构造函数是没必要的。
+ eslint: [`no-useless-constructor`](http://eslint.org/docs/rules/no-useless-constructor)
+
+ ```javascript
+ // bad
+ class Jedi {
+ constructor() {}
+
+ getName() {
+ return this.name;
+ }
+ }
+
+ // bad
+ class Rey extends Jedi {
+ constructor(...args) {
+ super(...args);
+ }
+ }
+
+ // good
+ class Rey extends Jedi {
+ constructor(...args) {
+ super(...args);
+ this.name = 'Rey';
+ }
+ }
+ ```
+
+
+ - [9.6](#classes--no-duplicate-members) 避免类成员重复。
+ eslint: [`no-dupe-class-members`](http://eslint.org/docs/rules/no-dupe-class-members)
+
+ > 为什么? 重复的类成员默认会使用最后一个——这肯定有一个错误存在。
+
+ ```javascript
+ // bad
+ class Foo {
+ bar() { return 1; }
+ bar() { return 2; }
+ }
+
+ // good
+ class Foo {
+ bar() { return 1; }
+ }
+
+ // good
+ class Foo {
+ bar() { return 2; }
+ }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 模块
+
+
+ - [10.1](#modules--use-them) 总是使用模块 (`import`/`export`) 而不是其他非标准模块系统。你可以编译为你喜欢的模块系统。
+
+ > 为什么? 模块就是未来,让我们开始迈向未来吧。
+
+ > NOTE: 模块命名?(这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致)
+
+ ```javascript
+ // bad
+ const AirbnbStyleGuide = require('./AirbnbStyleGuide');
+ module.exports = AirbnbStyleGuide.es6;
+
+ // ok
+ import AirbnbStyleGuide from './AirbnbStyleGuide';
+ export default AirbnbStyleGuide.es6;
+
+ // best
+ import { es6 } from './AirbnbStyleGuide';
+ export default es6;
+
+ // old: ES5 要注意
+ // - 模块应该以 `!` 开始,这保证了如果一个有问题的模块忘记包含最后的分号在合并后不会出现错误
+ // - 这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致
+ // - 加入一个名为noConflict()的方法来设置导出的模块为之前的版本并返回它
+ // - 总是在模块顶部声明 `'use strict';`
+ ```
+
+
+ - [10.2](#modules--no-wildcard) 不要使用通配符 import。
+
+ > 为什么? 这样能确保你只有一个默认 export。
+
+ ```javascript
+ // bad
+ import * as AirbnbStyleGuide from './AirbnbStyleGuide';
+
+ // good
+ import AirbnbStyleGuide from './AirbnbStyleGuide';
+ ```
+
+
+ - [10.3](#modules--no-export-from-import) 不要从 import 中直接 export。
+
+ > 为什么? 虽然一行代码简洁明了,但让 import 和 export 各司其职让事情能保持一致。
+
+ ```javascript
+ // bad
+ // filename es6.js
+ export { es6 as default } from './AirbnbStyleGuide';
+
+ // good
+ // filename es6.js
+ import { es6 } from './AirbnbStyleGuide';
+ export default es6;
+ ```
+
+
+ - [10.4](#modules--no-duplicate-imports) 一个模块只要一个 `import` 。
+ eslint: [`no-duplicate-imports`](http://eslint.org/docs/rules/no-duplicate-imports)
+
+ > 为什么? 同一模块多个 `import` 导入,会使代码更难维护。
+
+ ```javascript
+ // bad
+ import foo from 'foo';
+ // … some other imports … //
+ import { named1, named2 } from 'foo';
+
+ // good
+ import foo, { named1, named2 } from 'foo';
+
+ // good
+ import foo, {
+ named1,
+ named2,
+ } from 'foo';
+ ```
+
+
+ - [10.5](#modules--no-mutable-exports) 禁止 `export` 导出可变变量,应该使用常量(Functions/Classes 暂时例外)。
+ eslint: [`import/no-mutable-exports`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md)
+
+ > 为什么? 避免全局使用时出现问题,除了某些特定情况下确实要这样用。一般来说,`export` 应该输出常量。
+
+ ```javascript
+ // bad
+ var count = 3;
+ export { count }
+
+ // bad
+ let foo = 3;
+ export { foo };
+
+ // good
+ const foo = 3;
+ export { foo };
+
+ // valid
+ export const count = 1;
+ export function getCount () {};
+ export class Counter {};
+ ```
+
+
+ - [10.6](#modules--prefer-default-export) 单出口模块,更倾向设置为默认出口。
+ eslint: [`import/prefer-default-export`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md)
+
+ ```javascript
+ // bad
+ export function foo() {}
+
+ // good
+ export default function foo() {}
+ ```
+
+
+ - [10.7](#modules--imports-first) 把所有的 `import` 语句放在其他语句上面
+ eslint: [`import/imports-first`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/imports-first.md)
+
+ > 为什么? 把 `import` 提升, 保持将它们写在文件顶部是个好习惯。
+
+ ```javascript
+ // bad
+ import foo from 'foo';
+ foo.init();
+
+ import bar from 'bar';
+
+ // good
+ import foo from 'foo';
+ import bar from 'bar';
+
+ foo.init();
+ ```
+
+
+ - [10.8](#modules--multiline-imports-over-newlines) 多 `import` 入口,代码书写格式应与 `array` 和 `object` 保持一致。
+
+ > 为什么? 大括号代码块、缩进以及逗号都保持风格一致
+
+ ```javascript
+ // bad
+ import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
+
+ // good
+ import {
+ longNameA,
+ longNameB,
+ longNameC,
+ longNameD,
+ longNameE,
+ } from 'path';
+ ```
+
+
+ - [10.9](#modules--no-webpack-loader-syntax) 不允许在 `import` 语句里包含 webpack 加载器语法。
+ eslint: [`import/no-webpack-loader-syntax`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-webpack-loader-syntax.md)
+
+ > 为什么? 加载器语法要在 `webpack.config.js` 中使用
+
+ ```javascript
+ // bad
+ import fooSass from 'css!sass!foo.scss';
+ import barCss from 'style!css!bar.css';
+
+ // good
+ import fooSass from 'foo.scss';
+ import barCss from 'bar.css';
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## Iterators and Generators
+
+
+ - [11.1](#iterators--nope) 不要使用迭代器 iterators。使用高阶函数例如 `map()` 和 `reduce()` 替代 `for-in` or `for-of`。
+ eslint: [`no-iterator`](http://eslint.org/docs/rules/no-iterator.html) [`no-restricted-syntax`](http://eslint.org/docs/rules/no-restricted-syntax)
+
+ > 为什么? 这加强了我们不变的规则。处理纯函数的回调值更易读,这比它带来的副作用更重要。
+
+ > 使用迭代器 `map()` / `every()` / `filter()` / `find()` / `findIndex()` / `reduce()` / `some()` / ... 遍历数组,使用 `Object.keys()` / `Object.values()` / `Object.entries()` 遍历对象。
+ ```javascript
+ const numbers = [1, 2, 3, 4, 5];
+
+ // bad
+ let sum = 0;
+ for (let num of numbers) {
+ sum += num;
+ }
+ sum === 15;
+
+ // good
+ let sum = 0;
+ numbers.forEach(num => sum += num);
+ sum === 15;
+
+ // best (use the functional force)
+ const sum = numbers.reduce((total, num) => total + num, 0);
+ sum === 15;
+
+ // bad
+ const increasedByOne = [];
+ for (let i = 0; i < numbers.length; i++) {
+ increasedByOne.push(numbers[i] + 1);
+ }
+
+ // good
+ const increasedByOne = [];
+ numbers.forEach(num => increasedByOne.push(num + 1));
+
+ // best (keeping it functional)
+ const increasedByOne = numbers.map(num => num + 1);
+ ```
+
+
+ - [11.2](#generators--nope) 现在还不要使用 generators。
+
+ > 为什么? 因为它们现在还没法很好地编译到 ES5。 (译者注:目前(2016/03) Chrome 和 Node.js 的稳定版本都已支持 generators)
+
+
+ - [11.3](#generators--spacing) 如果你必须使用generators 或无视[generators 忠告](#generators--nope),那么请务必确保函数签名(function*)是适当的间距。
+ eslint: [`generator-star-spacing`](http://eslint.org/docs/rules/generator-star-spacing)
+
+ > 为什么? `function` and `*` 是同一个关键词的不同组成部分—— `*` 不是 `function` 修饰符, `function*` 是一种特定结构, 不同于 `function`。
+
+ ```javascript
+ // bad
+ function * foo() {
+ // ...
+ }
+
+ // bad
+ const bar = function * () {
+ // ...
+ };
+
+ // bad
+ const baz = function *() {
+ // ...
+ };
+
+ // bad
+ const quux = function*() {
+ // ...
+ };
+
+ // bad
+ function*foo() {
+ // ...
+ }
+
+ // bad
+ function *foo() {
+ // ...
+ }
+
+ // very bad
+ function
+ *
+ foo() {
+ // ...
+ }
+
+ // very bad
+ const wat = function
+ *
+ () {
+ // ...
+ };
+
+ // good
+ function* foo() {
+ // ...
+ }
+
+ // good
+ const foo = function* () {
+ // ...
+ };
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 属性
+
+
+ - [12.1](#properties--dot) 使用 `.` 符号来访问对象的属性。
+ eslint: [`dot-notation`](http://eslint.org/docs/rules/dot-notation.html)
+ jscs: [`requireDotNotation`](http://jscs.info/rule/requireDotNotation)
+
+ ```javascript
+ const luke = {
+ jedi: true,
+ age: 28,
+ };
+
+ // bad
+ const isJedi = luke['jedi'];
+
+ // good
+ const isJedi = luke.jedi;
+ ```
+
+
+ - [12.2](#properties--bracket) 当通过变量访问属性时使用中括号 `[]`。
+
+ ```javascript
+ const luke = {
+ jedi: true,
+ age: 28,
+ };
+
+ function getProp(prop) {
+ return luke[prop];
+ }
+
+ const isJedi = getProp('jedi');
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 变量
+
+
+ - [13.1](#variables--const) 总是使用 `const` 来声明变量,如果不这样做就会产生全局变量。我们需要避免全局命名空间的污染。[地球队长](http://www.wikiwand.com/en/Captain_Planet)已经警告过我们了。
+ (译注:全局,global 亦有全球的意思。地球队长的责任是保卫地球环境,所以他警告我们不要造成「全球」污染。)
+ eslint: [`no-undef`](http://eslint.org/docs/rules/no-undef) [`prefer-const`](http://eslint.org/docs/rules/prefer-const)
+
+ ```javascript
+ // bad
+ superPower = new SuperPower();
+
+ // good
+ const superPower = new SuperPower();
+ ```
+
+
+ - [13.2](#variables--one-const) 使用 `const` 声明每一个变量。
+ eslint: [`one-var`](http://eslint.org/docs/rules/one-var.html)
+ jscs: [`disallowMultipleVarDecl`](http://jscs.info/rule/disallowMultipleVarDecl)
+
+ > 为什么? 增加新变量将更容易,而且你永远不用再担心调换错 `;` or `,` ,并且 diff 工具下更少干扰。同时在 debugger 时,可以单步调试而不会一次跳过他们所有变量。
+
+ ```javascript
+ // bad
+ const items = getItems(),
+ goSportsTeam = true,
+ dragonball = 'z';
+
+ // bad
+ // (compare to above, and try to spot the mistake)
+ const items = getItems(),
+ goSportsTeam = true;
+ dragonball = 'z';
+
+ // good
+ const items = getItems();
+ const goSportsTeam = true;
+ const dragonball = 'z';
+ ```
+
+
+ - [13.3](#variables--const-let-group) 将所有的 `const` 和 `let` 分组
+
+ > 为什么? 当你需要把已赋值变量赋值给未赋值变量时非常有用。
+
+ ```javascript
+ // bad
+ let i, len, dragonball,
+ items = getItems(),
+ goSportsTeam = true;
+
+ // bad
+ let i;
+ const items = getItems();
+ let dragonball;
+ const goSportsTeam = true;
+ let len;
+
+ // good
+ const goSportsTeam = true;
+ const items = getItems();
+ let dragonball;
+ let i;
+ let length;
+ ```
+
+
+ - [13.4](#variables--define-where-used) 在你需要的地方给变量赋值,但请把它们放在一个合理的位置。
+
+ > 为什么? `let` 和 `const` 是块级作用域而不是函数作用域。
+
+ ```javascript
+ // bad - unnecessary function call
+ function checkName(hasName) {
+ const name = getName();
+
+ if (hasName === 'test') {
+ return false;
+ }
+
+ if (name === 'test') {
+ this.setName('');
+ return false;
+ }
+
+ return name;
+ }
+
+ // good
+ function checkName(hasName) {
+ if (hasName === 'test') {
+ return false;
+ }
+
+ const name = getName();
+
+ if (name === 'test') {
+ this.setName('');
+ return false;
+ }
+
+ return name;
+ }
+ ```
+
+
+ - [13.5](#variables--no-chain-assignment) 不使用链接变量赋值。
+
+ > 为什么? 链接变量赋值会创建隐式全局变量。
+
+ ```javascript
+ // bad
+ (function example() {
+ // JavaScript interprets this as
+ // let a = ( b = ( c = 1 ) );
+ // The let keyword only applies to variable a; variables b and c become
+ // global variables.
+ let a = b = c = 1;
+ }());
+
+ console.log(a); // undefined
+ console.log(b); // 1
+ console.log(c); // 1
+
+ // good
+ (function example() {
+ let a = 1;
+ let b = a;
+ let c = a;
+ }());
+
+ console.log(a); // undefined
+ console.log(b); // undefined
+ console.log(c); // undefined
+
+ // the same applies for `const`
+ ```
+
+
+ - [13.6](#variables--unary-increment-decrement) 避免使用一元递增和递减操作 (++, --) 。
+ eslint [`no-plusplus`](http://eslint.org/docs/rules/no-plusplus)
+
+ > 为什么? 一元递增和递减语句默认在自动分号插入处理下会有错误问题。而且它还会出现 `num += 1` 替代 `num ++` 的情况。不允许使用它们,也可以代码更健壮。
+
+ ```javascript
+ // bad
+
+ const array = [1, 2, 3];
+ let num = 1;
+ num++;
+ --num;
+
+ let sum = 0;
+ let truthyCount = 0;
+ for (let i = 0; i < array.length; i++) {
+ let value = array[i];
+ sum += value;
+ if (value) {
+ truthyCount++;
+ }
+ }
+
+ // good
+
+ const array = [1, 2, 3];
+ let num = 1;
+ num += 1;
+ num -= 1;
+
+ const sum = array.reduce((a, b) => a + b, 0);
+ const truthyCount = array.filter(Boolean).length;
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## Hoisting
+
+
+ - [14.1](#hoisting--about) `var` 声明会被提升至该作用域的顶部,但它们赋值不会提升。`let` 和 `const` 被赋予了一种称为「[暂时性死区(Temporal Dead Zones, TDZ)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let)」的概念。这对于了解为什么 [type of 不再安全](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15)相当重要。
+
+ ```javascript
+ // 我们知道这样运行不了(假设 notDefined 不是全局变量)
+ function example() {
+ console.log(notDefined); // => throws a ReferenceError
+ }
+
+ // 由于变量提升的原因,
+ // 在引用变量后再声明变量是可以运行的。
+ // NOTE: 变量赋值 `true` 的操作不会被提升。
+ function example() {
+ console.log(declaredButNotAssigned); // => undefined
+ var declaredButNotAssigned = true;
+ }
+
+ // 编译器会把函数声明提升到作用域的顶层,
+ // 这意味着我们的例子可以改写成这样:
+ function example() {
+ let declaredButNotAssigned;
+ console.log(declaredButNotAssigned); // => undefined
+ declaredButNotAssigned = true;
+ }
+
+ // 使用 const 和 let
+ function example() {
+ console.log(declaredButNotAssigned); // => throws a ReferenceError
+ console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
+ const declaredButNotAssigned = true;
+ }
+ ```
+
+
+ - [14.2](#hoisting--anon-expressions) 匿名函数表达式的变量名会被提升,但函数体并不会。
+
+ ```javascript
+ function example() {
+ console.log(anonymous); // => undefined
+
+ anonymous(); // => TypeError anonymous is not a function
+
+ var anonymous = function () {
+ console.log('anonymous function expression');
+ };
+ }
+ ```
+
+
+ - [14.3](#hoisting--named-expresions) 命名的函数表达式的变量名会被提升,但函数名和函数体并不会。
+
+ ```javascript
+ function example() {
+ console.log(named); // => undefined
+
+ named(); // => TypeError named is not a function
+
+ superPower(); // => ReferenceError superPower is not defined
+
+ var named = function superPower() {
+ console.log('Flying');
+ };
+ }
+
+ // the same is true when the function name
+ // is the same as the variable name.
+ function example() {
+ console.log(named); // => undefined
+
+ named(); // => TypeError named is not a function
+
+ var named = function named() {
+ console.log('named');
+ };
+ }
+ ```
+
+
+ - [14.4](#hoisting--declarations) 函数声明的名称和函数体都会被提升。
+
+ ```javascript
+ function example() {
+ superPower(); // => Flying
+
+ function superPower() {
+ console.log('Flying');
+ }
+ }
+ ```
+
+ - For more information refer to [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting/) by [Ben Cherry](http://www.adequatelygood.com/).
+
+ - 想了解更多信息,参考 [Ben Cherry](http://www.adequatelygood.com/) 的 [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting)。
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 比较运算符 & 等号
+
+
+ - [15.1](#comparison--eqeqeq) 优先使用 `===` 和 `!==` 而不是 `==` 和 `!=` 。
+ eslint: [`eqeqeq`](http://eslint.org/docs/rules/eqeqeq.html)
+
+
+ - [15.2](#comparison--if) 条件表达式例如 `if` 语句通过抽象方法 `ToBoolean` 强制计算它们的表达式并且总是遵守下面的规则:
+
+ + **Objects 对象** 被计算为 **true**
+ + **Undefined** 被计算为 **false**
+ + **Null** 被计算为 **false**
+ + **Booleans 布尔值** 被计算为 **布尔的值**
+ + **Numbers 数字** 如果是 **+0、-0、或 NaN** 被计算为 **false**, 否则为 **true**
+ + **Strings 字符串** 如果是空字符串 `''` 被计算为 **false**,否则为 **true**
+
+ ```javascript
+ if ([0] && []) {
+ // true
+ // an array (even an empty one) is an object, objects will evaluate to true
+ }
+ ```
+
+
+ - [15.3](#comparison--shortcuts) 布尔值使用简写,明确使用数字和字符串比较除外。
+
+ ```javascript
+ // bad
+ if (isValid === true) {
+ // ...
+ }
+
+ // good
+ if (isValid) {
+ // ...
+ }
+
+ // bad
+ if (name) {
+ // ...
+ }
+
+ // good
+ if (name !== '') {
+ // ...
+ }
+
+ // bad
+ if (collection.length) {
+ // ...
+ }
+
+ // good
+ if (collection.length > 0) {
+ // 为什么用简写是 bad ???
+ // ...
+ }
+ ```
+
+
+ - [15.4](#comparison--moreinfo) 想了解更多信息,参考 Angus Croll 的 [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108)。
+
+
+ - [15.5](#comparison--switch-blocks) 如果 `case` 以及 `default` 中包含声明部分 (e.g. `let`, `const`, `function`, and `class`),使用大括号以创建块级作用域。
+
+ > 为什么? 声明在整个 `switch` 代码块中可见,但只有在执行到 `case` 并赋值时才初始化。这可能在多 `case` 中导致重复定义从而出现问题。
+
+ eslint: [`no-case-declarations`](http://eslint.org/docs/rules/no-case-declarations.html)
+
+ ```javascript
+ // bad
+ switch (foo) {
+ case 1:
+ let x = 1;
+ break;
+ case 2:
+ const y = 2;
+ break;
+ case 3:
+ function f() {
+ // ...
+ }
+ break;
+ default:
+ class C {}
+ }
+
+ // good 如果有声明,就使用大括号括起来
+ switch (foo) {
+ case 1: {
+ let x = 1;
+ break;
+ }
+ case 2: {
+ const y = 2;
+ break;
+ }
+ case 3: {
+ function f() {
+ // ...
+ }
+ break;
+ }
+ case 4:
+ bar();
+ break;
+ default: {
+ class C {}
+ }
+ }
+ ```
+
+
+ - [15.6](#comparison--nested-ternaries) 不要嵌套使用三元表达式,要单个使用。
+
+ eslint rules: [`no-nested-ternary`](http://eslint.org/docs/rules/no-nested-ternary.html).
+
+ ```javascript
+ // bad
+ const foo = maybe1 > maybe2
+ ? "bar"
+ : value1 > value2 ? "baz" : null;
+
+ // better
+ const maybeNull = value1 > value2 ? 'baz' : null;
+
+ const foo = maybe1 > maybe2
+ ? 'bar'
+ : maybeNull;
+
+ // best
+ const maybeNull = value1 > value2 ? 'baz' : null;
+
+ const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
+ ```
+
+
+ - [15.7](#comparison--unneeded-ternary) 避免使用不必要的三元表达式
+
+ eslint rules: [`no-unneeded-ternary`](http://eslint.org/docs/rules/no-unneeded-ternary.html).
+
+ ```javascript
+ // bad
+ const foo = a ? a : b;
+ const bar = c ? true : false;
+ const baz = c ? false : true;
+
+ // good
+ const foo = a || b;
+ const bar = !!c;
+ const baz = !c;
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 代码块
+
+
+ - [16.1](#blocks--braces) 使用大括号包裹所有的多行代码块。
+
+ ```javascript
+ // bad
+ if (test)
+ return false;
+
+ // good
+ if (test) return false;
+
+ // good
+ if (test) {
+ return false;
+ }
+
+ // bad
+ function foo() { return false; }
+
+ // good
+ function bar() {
+ return false;
+ }
+ ```
+
+
+ - [16.2](#blocks--cuddled-elses) 如果通过 `if` 和 `else` 使用多行代码块,把 `else` 放在 `if` 代码块关闭括号的同一行。
+
+ ```javascript
+ // bad
+ if (test) {
+ thing1();
+ thing2();
+ }
+ else {
+ thing3();
+ }
+
+ // good
+ if (test) {
+ thing1();
+ thing2();
+ } else {
+ thing3();
+ }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 注释
+
+
+ - [17.1](#comments--multiline) 使用 `/** ... */` 作为多行注释。包含描述、指定所有参数和返回值的类型和值。
+
+ ```javascript
+ // bad
+ // make() returns a new element
+ // based on the passed in tag name
+ //
+ // @param {String} tag
+ // @return {Element} element
+ function make(tag) {
+
+ // ...
+
+ return element;
+ }
+
+ // good
+ /**
+ * make() returns a new element
+ * based on the passed-in tag name
+ *
+ * @param {String} tag
+ * @return {Element} element
+ */
+ function make(tag) {
+
+ // ...
+
+ return element;
+ }
+ ```
+
+
+ - [17.2](#comments--singleline) 单行注释使用 `//`,后紧跟一空格。在评论对象上面另起一行使用单行注释。在注释前插入空行。
+
+ ```javascript
+ // bad
+ const active = true; // is current tab
+
+ // good
+ // is current tab
+ const active = true;
+
+ // bad
+ function getType() {
+ console.log('fetching type...');
+ // set the default type to 'no type'
+ const type = this.type || 'no type';
+
+ return type;
+ }
+
+ // good
+ function getType() {
+ console.log('fetching type...');
+
+ // set the default type to 'no type'
+ const type = this.type || 'no type';
+
+ return type;
+ }
+
+ // also good
+ function getType() {
+ // set the default type to 'no type'
+ const type = this.type || 'no type';
+
+ return type;
+ }
+ ```
+
+ - [17.3](#comments--spaces) 注释以空格开始,这样更容易阅读。
+ eslint: [`spaced-comment`](http://eslint.org/docs/rules/spaced-comment)
+
+ ```javascript
+ // bad
+ //is current tab
+ const active = true;
+
+ // good
+ // is current tab
+ const active = true;
+
+ // bad
+ /**
+ *make() returns a new element
+ *based on the passed-in tag name
+ */
+ function make(tag) {
+
+ // ...
+
+ return element;
+ }
+
+ // good
+ /**
+ * make() returns a new element
+ * based on the passed-in tag name
+ */
+ function make(tag) {
+
+ // ...
+
+ return element;
+ }
+ ```
+
+
+ - [17.4](#comments--actionitems) 给注释增加 `FIXME` 或 `TODO` 的前缀可以帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。这将有别于常见的注释,因为它们是可操作的。使用 `FIXME -- need to figure this out` 或者 `TODO -- need to implement`。
+
+
+ - [17.5](#comments--fixme) 使用 `// FIXME`: 标注问题。
+
+ ```javascript
+ class Calculator extends Abacus {
+ constructor() {
+ super();
+
+ // FIXME: shouldn't use a global here
+ total = 0;
+ }
+ }
+ ```
+
+
+ - [17.6](#comments--todo) 使用 `// TODO`: 标注问题还需要解决。
+
+ ```javascript
+ class Calculator extends Abacus {
+ constructor() {
+ super();
+
+ // TODO: total should be configurable by an options param
+ this.total = 0;
+ }
+ }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 空白
+
+
+ - [18.1](#whitespace--spaces) 使用 2 个空格作为缩进。
+ eslint: [`indent`](http://eslint.org/docs/rules/indent.html)
+ jscs: [`validateIndentation`](http://jscs.info/rule/validateIndentation)
+
+ ```javascript
+ // bad
+ function foo() {
+ ∙∙∙∙let name;
+ }
+
+ // bad
+ function bar() {
+ ∙let name;
+ }
+
+ // good
+ function baz() {
+ ∙∙let name;
+ }
+ ```
+
+
+ - [18.2](#whitespace--before-blocks) 在大括号前放一个空格。
+ eslint: [`space-before-blocks`](http://eslint.org/docs/rules/space-before-blocks.html)
+ jscs: [`requireSpaceBeforeBlockStatements`](http://jscs.info/rule/requireSpaceBeforeBlockStatements)
+
+ ```javascript
+ // bad
+ function test(){
+ console.log('test');
+ }
+
+ // good
+ function test() {
+ console.log('test');
+ }
+
+ // bad
+ dog.set('attr',{
+ age: '1 year',
+ breed: 'Bernese Mountain Dog',
+ });
+
+ // good
+ dog.set('attr', {
+ age: '1 year',
+ breed: 'Bernese Mountain Dog',
+ });
+ ```
+
+
+ - [18.3](#whitespace--around-keywords) 在控制语句(`if`、`while` 等)的小括号前放一个空格。在函数调用及声明时,函数名与参数列表之间不要空格[7.11](#functions--signature-spacing)。
+ eslint: [`keyword-spacing`](http://eslint.org/docs/rules/keyword-spacing.html)
+ jscs: [`requireSpaceAfterKeywords`](http://jscs.info/rule/requireSpaceAfterKeywords)
+
+ ```javascript
+ // bad
+ if(isJedi) {
+ fight();
+ }
+
+ // good
+ if (isJedi) {
+ fight();
+ }
+
+ // bad
+ function fight () {
+ console.log ('Swooosh!');
+ }
+
+ // good
+ function fight() {
+ console.log('Swooosh!');
+ }
+ ```
+
+
+ - [18.4](#whitespace--infix-ops) 使用空格把运算符隔开。
+ eslint: [`space-infix-ops`](http://eslint.org/docs/rules/space-infix-ops.html)
+ jscs: [`requireSpaceBeforeBinaryOperators`](http://jscs.info/rule/requireSpaceBeforeBinaryOperators), [`requireSpaceAfterBinaryOperators`](http://jscs.info/rule/requireSpaceAfterBinaryOperators)
+
+ ```javascript
+ // bad
+ const x=y+5;
+
+ // good
+ const x = y + 5;
+ ```
+
+
+ - [18.5](#whitespace--newline-at-end) 在文件末尾插入一个空行。
+ eslint: [`eol-last`](https://github.com/eslint/eslint/blob/master/docs/rules/eol-last.md)
+
+ ```javascript
+ // bad
+ import { es6 } from './AirbnbStyleGuide';
+ // ...
+ export default es6;
+ ```
+
+ ```javascript
+ // bad
+ import { es6 } from './AirbnbStyleGuide';
+ // ...
+ export default es6;↵
+ ↵
+ ```
+
+ ```javascript
+ // good
+ import { es6 } from './AirbnbStyleGuide';
+ // ...
+ export default es6;↵
+ ```
+
+
+ - [18.6](#whitespace--chains) 在使用长方法链时进行缩进。以 `.` 起行并缩进,强调这是方法调用而不是新语句。
+ 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)
+
+ ```javascript
+ // bad
+ $('#items').find('.selected').highlight().end().find('.open').updateCount();
+
+ // bad
+ $('#items').
+ find('.selected').
+ highlight().
+ end().
+ find('.open').
+ updateCount();
+
+ // good
+ $('#items')
+ .find('.selected')
+ .highlight()
+ .end()
+ .find('.open')
+ .updateCount();
+
+ // bad
+ const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
+ .attr('width', (radius + margin) * 2).append('svg:g')
+ .attr('transform', `translate(${radius + margin},${radius + margin})`)
+ .call(tron.led);
+
+ // good
+ const leds = stage.selectAll('.led')
+ .data(data)
+ .enter().append('svg:svg')
+ .classed('led', true)
+ .attr('width', (radius + margin) * 2)
+ .append('svg:g')
+ .attr('transform', `translate(${radius + margin},${radius + margin})`)
+ .call(tron.led);
+
+ // good
+ const leds = stage.selectAll('.led').data(data);
+ ```
+
+
+ - [18.7](#whitespace--after-blocks) 在块末和新语句前插入空行。
+ jscs: [`requirePaddingNewLinesAfterBlocks`](http://jscs.info/rule/requirePaddingNewLinesAfterBlocks)
+
+ ```javascript
+ // bad
+ if (foo) {
+ return bar;
+ }
+ return baz;
+
+ // good
+ if (foo) {
+ return bar;
+ }
+
+ return baz;
+
+ // bad
+ const obj = {
+ foo() {
+ },
+ bar() {
+ },
+ };
+ return obj;
+
+ // good
+ const obj = {
+ foo() {
+ },
+
+ bar() {
+ },
+ };
+
+ return obj;
+
+ // bad
+ const arr = [
+ function foo() {
+ },
+ function bar() {
+ },
+ ];
+ return arr;
+
+ // good
+ const arr = [
+ function foo() {
+ },
+
+ function bar() {
+ },
+ ];
+
+ return arr;
+ ```
+
+
+ - [18.8](#whitespace--padded-blocks) 不要使用空白行紧邻块作用域填充空间。
+ eslint: [`padded-blocks`](http://eslint.org/docs/rules/padded-blocks.html)
+ jscs: [`disallowPaddingNewlinesInBlocks`](http://jscs.info/rule/disallowPaddingNewlinesInBlocks)
+
+ ```javascript
+ // bad
+ function bar() {
+
+ console.log(foo);
+
+ }
+
+ // also bad
+ if (baz) {
+
+ console.log(qux);
+ } else {
+ console.log(foo);
+
+ }
+
+ // good
+ function bar() {
+ console.log(foo);
+ }
+
+ // good
+ if (baz) {
+ console.log(qux);
+ } else {
+ console.log(foo);
+ }
+ ```
+
+
+ - [18.9](#whitespace--in-parens) 不要在圆括号(parentheses)内侧两边填充空格,如函数调用、条件判断等。
+ eslint: [`space-in-parens`](http://eslint.org/docs/rules/space-in-parens.html)
+ jscs: [`disallowSpacesInsideParentheses`](http://jscs.info/rule/disallowSpacesInsideParentheses)
+
+ ```javascript
+ // bad
+ function bar( foo ) {
+ return foo;
+ }
+
+ // good
+ function bar(foo) {
+ return foo;
+ }
+
+ // bad
+ if ( foo ) {
+ console.log(foo);
+ }
+
+ // good
+ if (foo) {
+ console.log(foo);
+ }
+ ```
+
+
+ - [18.10](#whitespace--in-brackets) 不要在中括号(brackets)内侧左右两边填充空格。
+ eslint: [`array-bracket-spacing`](http://eslint.org/docs/rules/array-bracket-spacing.html)
+ jscs: [`disallowSpacesInsideArrayBrackets`](http://jscs.info/rule/disallowSpacesInsideArrayBrackets)
+
+ ```javascript
+ // bad
+ const foo = [ 1, 2, 3 ];
+ console.log(foo[ 0 ]);
+
+ // good
+ const foo = [1, 2, 3];
+ console.log(foo[0]);
+ ```
+
+
+ - [18.11](#whitespace--in-braces) 在大括号(curly braces)内侧两边添加空格。
+ eslint: [`object-curly-spacing`](http://eslint.org/docs/rules/object-curly-spacing.html)
+ jscs: [`requireSpacesInsideObjectBrackets`](http://jscs.info/rule/requireSpacesInsideObjectBrackets)
+
+ ```javascript
+ // bad
+ const foo = {clark: 'kent'};
+
+ // good
+ const foo = { clark: 'kent' };
+ ```
+
+
+ - [18.12](#whitespace--max-len) 避免一行代码过长,超过100个字符(包括空格)。Note: 参看 [strings--line-length](#strings--line-length),过长字符应该分行处理。
+ eslint: [`max-len`](http://eslint.org/docs/rules/max-len.html)
+ jscs: [`maximumLineLength`](http://jscs.info/rule/maximumLineLength)
+
+ > 为什么? 为了确保可读性、可维护性。注:作为一个良好的习惯,虽然显示器界面越来越大了,但代码为了通用性维护,如 shell 内也可以修改维护,那么有必要处理过长代码段。
+
+ ```javascript
+ // bad
+ const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy;
+
+ // bad
+ $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));
+
+ // good
+ const foo = jsonData
+ && jsonData.foo
+ && jsonData.foo.bar
+ && jsonData.foo.bar.baz
+ && jsonData.foo.bar.baz.quux
+ && jsonData.foo.bar.baz.quux.xyzzy;
+
+ // good
+ $.ajax({
+ method: 'POST',
+ url: 'https://airbnb.com/',
+ data: { name: 'John' },
+ })
+ .done(() => console.log('Congratulations!'))
+ .fail(() => console.log('You have failed this city.'));
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 逗号
+
+
+ - [19.1](#commas--leading-trailing) 行首逗号:**不需要**。
+ eslint: [`comma-style`](http://eslint.org/docs/rules/comma-style.html)
+ jscs: [`requireCommaBeforeLineBreak`](http://jscs.info/rule/requireCommaBeforeLineBreak)
+
+ ```javascript
+ // bad
+ const story = [
+ once
+ , upon
+ , aTime
+ ];
+
+ // good
+ const story = [
+ once,
+ upon,
+ aTime,
+ ];
+
+ // bad
+ const hero = {
+ firstName: 'Ada'
+ , lastName: 'Lovelace'
+ , birthYear: 1815
+ , superPower: 'computers'
+ };
+
+ // good
+ const hero = {
+ firstName: 'Ada',
+ lastName: 'Lovelace',
+ birthYear: 1815,
+ superPower: 'computers',
+ };
+ ```
+
+
+ - [19.2](#commas--dangling) 增加结尾的逗号: **需要**。
+ eslint: [`comma-dangle`](http://eslint.org/docs/rules/comma-dangle.html)
+ jscs: [`requireTrailingComma`](http://jscs.info/rule/requireTrailingComma)
+
+ > 为什么? 这会让 git diffs 更干净。另外,像 babel 这样的转译器会移除结尾多余的逗号,也就是说你不必担心老旧浏览器的[尾逗号问题](https://github.com/airbnb/javascript/blob/es5-deprecated/es5/README.md#commas)。
+
+ ```diff
+ // bad - git diff without trailing comma
+ const hero = {
+ firstName: 'Florence',
+ - lastName: 'Nightingale'
+ + lastName: 'Nightingale',
+ + inventorOf: ['coxcomb chart', 'modern nursing']
+ };
+
+ // good - git diff with trailing comma
+ const hero = {
+ firstName: 'Florence',
+ lastName: 'Nightingale',
+ + inventorOf: ['coxcomb chart', 'modern nursing'],
+ };
+ ```
+
+ ```javascript
+ // bad
+ const hero = {
+ firstName: 'Dana',
+ lastName: 'Scully'
+ };
+
+ const heroes = [
+ 'Batman',
+ 'Superman'
+ ];
+
+ // good
+ const hero = {
+ firstName: 'Dana',
+ lastName: 'Scully',
+ };
+
+ const heroes = [
+ 'Batman',
+ 'Superman',
+ ];
+
+ // bad
+ function createHero(
+ firstName,
+ lastName,
+ inventorOf
+ ) {
+ // does nothing
+ }
+
+ // good
+ function createHero(
+ firstName,
+ lastName,
+ inventorOf,
+ ) {
+ // does nothing
+ }
+
+ // good (note that a comma must not appear after a "rest" element)
+ // NOTE: rest 元素后不能出现逗号
+ function createHero(
+ firstName,
+ lastName,
+ inventorOf,
+ ...heroArgs
+ ) {
+ // does nothing
+ }
+
+ // bad
+ createHero(
+ firstName,
+ lastName,
+ inventorOf
+ );
+
+ // good
+ createHero(
+ firstName,
+ lastName,
+ inventorOf,
+ );
+
+ // good (note that a comma must not appear after a "rest" element)
+ createHero(
+ firstName,
+ lastName,
+ inventorOf,
+ ...heroArgs
+ );
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 分号
+
+
+ - [20.1](#semicolons--required) **使用分号**
+ eslint: [`semi`](http://eslint.org/docs/rules/semi.html)
+ jscs: [`requireSemicolons`](http://jscs.info/rule/requireSemicolons)
+
+ ```javascript
+ // bad
+ (function () {
+ const name = 'Skywalker'
+ return name
+ })()
+
+ // good
+ (function () {
+ const name = 'Skywalker';
+ return name;
+ }());
+
+ // good (防止函数在两个 IIFE 串联时其中一个被错误当成另一个的参数处理)
+ // NOTE: 箭头函数参数省略,使用圆括号包裹处理
+ ;((() => {
+ const name = 'Skywalker';
+ return name;
+ })());
+ ```
+
+ [Read more](https://stackoverflow.com/questions/7365172/semicolon-before-self-invoking-function/7365214%237365214).
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 类型转换
+
+
+ - [21.1](#coercion--explicit) 在语句开头执行类型转换。
+
+
+ - [21.2](#coercion--strings) 处理字符串:
+
+ ```javascript
+ // => this.reviewScore = 9;
+
+ // bad
+ const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf()
+
+ // bad
+ const totalScore = this.reviewScore.toString(); // isn't guaranteed to return a string
+
+ // good
+ const totalScore = String(this.reviewScore);
+ ```
+
+
+ - [21.3](#coercion--numbers) 处理数字:使用 `Number` 转换数字类型。如果要使用 `parseInt` 转换,就总是带着类型转换的基数。
+ eslint: [`radix`](http://eslint.org/docs/rules/radix)
+
+ ```javascript
+ const inputValue = '4';
+
+ // bad
+ const val = new Number(inputValue);
+
+ // bad
+ const val = +inputValue;
+
+ // bad
+ const val = inputValue >> 0;
+
+ // bad
+ const val = parseInt(inputValue);
+
+ // good
+ const val = Number(inputValue);
+
+ // good
+ const val = parseInt(inputValue, 10);
+ ```
+
+
+ - [21.4](#coercion--comment-deviations) 如果因为某些原因 parseInt 成为你所做的事的瓶颈而需要使用位操作解决[性能问题](http://jsperf.com/coercion-vs-casting/3)时,留个注释说清楚原因和你的目的。
+
+ ```javascript
+ // good
+ /**
+ * 使用 parseInt 导致我的程序变慢,
+ * 改成使用位操作转换数字快多了。
+ */
+ const val = inputValue >> 0;
+ ```
+
+
+ - [21.5](#coercion--bitwise) NOTE: 使用位操作运算符要特别小心。数字会被当成 [64 位值](http://es5.github.io/#x4.3.19),但是位操作运算符总是返回 32 位的整数([参考](http://es5.github.io/#x11.7))。位操作处理大于 32 位的整数值时还会导致意料之外的行为。[关于这个问题的讨论](https://github.com/airbnb/javascript/issues/109)。最大的 32 位整数是 2,147,483,647:
+
+ ```javascript
+ 2147483647 >> 0; // => 2147483647
+ 2147483648 >> 0; // => -2147483648
+ 2147483649 >> 0; // => -2147483647
+ ```
+
+
+ - [21.6](#coercion--booleans) 处理布尔值:
+
+ ```javascript
+ const age = 0;
+
+ // bad
+ const hasAge = new Boolean(age);
+
+ // good
+ const hasAge = Boolean(age);
+
+ // best
+ const hasAge = !!age;
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 命名规则
+
+
+ - [22.1](#naming--descriptive) 避免单字母命名。命名应具备描述性。
+ eslint: [`id-length`](http://eslint.org/docs/rules/id-length)
+
+ ```javascript
+ // bad
+ function q() {
+ // ...
+ }
+
+ // good
+ function query() {
+ // ...
+ }
+ ```
+
+
+ - [22.2](#naming--camelCase) 使用驼峰式(camelCase、小驼峰)命名变量、对象、函数和实例。
+ eslint: [`camelcase`](http://eslint.org/docs/rules/camelcase.html)
+ jscs: [`requireCamelCaseOrUpperCaseIdentifiers`](http://jscs.info/rule/requireCamelCaseOrUpperCaseIdentifiers)
+
+ ```javascript
+ // bad
+ const OBJEcttsssss = {};
+ const this_is_my_object = {};
+ function c() {}
+
+ // good
+ const thisIsMyObject = {};
+ function thisIsMyFunction() {}
+ ```
+
+
+ - [22.3](#naming--PascalCase) 使用帕斯卡式(PascalCase、大驼峰式)命名构造函数或类。
+ eslint: [`new-cap`](http://eslint.org/docs/rules/new-cap.html)
+ jscs: [`requireCapitalizedConstructors`](http://jscs.info/rule/requireCapitalizedConstructors)
+
+ Pascal命名法:单字之间不以空格断开或连接号(-)、底线(_)连结,第一个单字首字母采用大写字母;后续单字的首字母亦用大写字母
+
+ ```javascript
+ // bad
+ function user(options) {
+ this.name = options.name;
+ }
+
+ const bad = new user({
+ name: 'nope',
+ });
+
+ // good
+ class User {
+ constructor(options) {
+ this.name = options.name;
+ }
+ }
+
+ const good = new User({
+ name: 'yup',
+ });
+ ```
+
+
+ - [22.4](#naming--leading-underscore) 不要使用尾随或前导下划线来命名私有属性。
+ eslint: [`no-underscore-dangle`](http://eslint.org/docs/rules/no-underscore-dangle.html)
+ jscs: [`disallowDanglingUnderscores`](http://jscs.info/rule/disallowDanglingUnderscores)
+
+ > 为什么? JavaScript没有在属性或方法方面的隐私权的概念。虽然一个领先的下划线是一个共同的公约,意思是“私人”,事实上,这些属性是完全公开的,因此,是你的公共API合同的一部分。这个约定可能会导致开发人员错误地认为一个变化不算是中断,或者不需要测试。TL;DR:如果你想要的东西是“私人的”,它不应该可见。
+
+ ```javascript
+ // bad
+ this.__firstName__ = 'Panda';
+ this.firstName_ = 'Panda';
+ this._firstName = 'Panda';
+
+ // good
+ this.firstName = 'Panda';
+ ```
+
+
+ - [22.5](#naming--self-this) 别保存 `this` 的引用。应使用箭头函数或函数绑定 [Function#bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)。
+ jscs: [`disallowNodeTypes`](http://jscs.info/rule/disallowNodeTypes)
+
+ ```javascript
+ // bad
+ function foo() {
+ const self = this;
+ return function () {
+ console.log(self);
+ };
+ }
+
+ // bad
+ function foo() {
+ const that = this;
+ return function () {
+ console.log(that);
+ };
+ }
+
+ // good
+ function foo() {
+ return () => {
+ console.log(this);
+ };
+ }
+ ```
+
+
+ - [22.6](#naming--filename-matches-export) 如果你的文件只输出一个类,那你的文件名必须和类名完全保持一致。
+
+ ```javascript
+ // file 1 contents
+ class CheckBox {
+ // ...
+ }
+ export default CheckBox;
+
+ // file 2 contents
+ export default function fortyTwo() { return 42; }
+
+ // file 3 contents
+ export default function insideDirectory() {}
+
+ // in some other file
+ // bad
+ import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename
+ import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export
+ import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export
+
+ // bad
+ import CheckBox from './check_box'; // PascalCase import/export, snake_case filename
+ import forty_two from './forty_two'; // snake_case import/filename, camelCase export
+ import inside_directory from './inside_directory'; // snake_case import, camelCase export
+ import index from './inside_directory/index'; // requiring the index file explicitly
+ import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly
+
+ // good
+ import CheckBox from './CheckBox'; // PascalCase export/import/filename
+ import fortyTwo from './fortyTwo'; // camelCase export/import/filename
+ import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
+ // ^ supports both insideDirectory.js and insideDirectory/index.js
+ ```
+
+
+ - [22.7](#naming--camelCase-default-export) 当你导出默认的函数时使用驼峰式命名camelCase。你的文件名必须和函数名完全保持一致。
+
+ ```javascript
+ function makeStyleGuide() {
+ // ...
+ }
+
+ export default makeStyleGuide;
+ ```
+
+
+ - [22.8](#naming--PascalCase-singleton) 当你导出构造函数、类、单例、函数库、空对象时使用帕斯卡式命名PascalCase。
+
+ ```javascript
+ const AirbnbStyleGuide = {
+ es6: {
+ },
+ };
+
+ export default AirbnbStyleGuide;
+ ```
+
+
+ - [22.9](#naming--Acronyms-and-Initialisms) 缩写词要么全大写,要么全小写。
+
+ > 为什么? 名字的目的是提升可读性,而不是给电脑算法的。
+
+ ```javascript
+ // bad
+ import SmsContainer from './containers/SmsContainer';
+
+ // bad
+ const HttpRequests = [
+ // ...
+ ];
+
+ // good
+ import SMSContainer from './containers/SMSContainer';
+
+ // good
+ const HTTPRequests = [
+ // ...
+ ];
+
+ // best
+ import TextMessageContainer from './containers/TextMessageContainer';
+
+ // best
+ const Requests = [
+ // ...
+ ];
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 存取器
+
+
+ - [23.1](#accessors--not-required) 属性的存取函数不是必须的。
+
+
+ - [23.2](#accessors--no-getters-setters) 不要使用 getters/setters 有可能引起副作用,很难测试、维护、调试。如果你需要存取函数时使用 `getVal()` 和 `setVal(value)`。
+
+ ```javascript
+ // bad
+ class Dragon {
+ get age() {
+ // ...
+ }
+
+ set age(value) {
+ // ...
+ }
+ }
+
+ // good
+ class Dragon {
+ getAge() {
+ // ...
+ }
+
+ setAge(value) {
+ // ...
+ }
+ }
+ ```
+
+
+ - [23.3](#accessors--boolean-prefix) 如果属性/方法是布尔值,使用 `isVal()` 或 `hasVal()` 来处理。
+
+ ```javascript
+ // bad
+ if (!dragon.age()) {
+ return false;
+ }
+
+ // good
+ if (!dragon.hasAge()) {
+ return false;
+ }
+ ```
+
+
+ - [23.4](#accessors--consistent) 可以创建 `get()` 和 `set()` 函数,但要保持一致。
+
+ ```javascript
+ class Jedi {
+ constructor(options = {}) {
+ const lightsaber = options.lightsaber || 'blue';
+ this.set('lightsaber', lightsaber);
+ }
+
+ set(key, val) {
+ this[key] = val;
+ }
+
+ get(key) {
+ return this[key];
+ }
+ }
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 事件
+
+
+ - [24.1](#events--hash) 当给事件附加数据时(无论是 DOM 事件还是私有事件),传入一个哈希而不是原始值。这样可以让后面的贡献者增加更多数据到事件数据而无需找出并更新事件的每一个处理器。例如,不好的写法:
+
+ ```javascript
+ // bad
+ $(this).trigger('listingUpdated', listing.id);
+
+ // ...
+
+ $(this).on('listingUpdated', (e, listingId) => {
+ // do something with listingId
+ });
+ ```
+
+ prefer 更好的写法:
+
+ ```javascript
+ // good
+ $(this).trigger('listingUpdated', { listingId: listing.id });
+
+ // ...
+
+ $(this).on('listingUpdated', (e, data) => {
+ // do something with data.listingId
+ });
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## jQuery
+
+
+ - [25.1](#jquery--dollar-prefix) 使用 `$` 作为存储 jQuery 对象的变量名前缀。
+ jscs: [`requireDollarBeforejQueryAssignment`](http://jscs.info/rule/requireDollarBeforejQueryAssignment)
+
+ ```javascript
+ // bad
+ const sidebar = $('.sidebar');
+
+ // good
+ const $sidebar = $('.sidebar');
+
+ // good
+ const $sidebarBtn = $('.sidebar-btn');
+ ```
+
+
+ - [25.2](#jquery--cache) 缓存 jQuery 查询。
+
+ ```javascript
+ // bad
+ function setSidebar() {
+ $('.sidebar').hide();
+
+ // ...
+
+ $('.sidebar').css({
+ 'background-color': 'pink',
+ });
+ }
+
+ // good
+ function setSidebar() {
+ const $sidebar = $('.sidebar');
+ $sidebar.hide();
+
+ // ...
+
+ $sidebar.css({
+ 'background-color': 'pink',
+ });
+ }
+ ```
+
+
+ - [25.3](#jquery--queries) 对 DOM 查询使用层叠 `$('.sidebar ul')` 或 父元素 > 子元素 `$('.sidebar > ul')`。
+ [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)
+
+
+ - [25.4](#jquery--find) 对有作用域的 jQuery 对象查询使用 `find`。
+
+ ```javascript
+ // bad
+ $('ul', '.sidebar').hide();
+
+ // bad
+ $('.sidebar').find('ul').hide();
+
+ // good
+ $('.sidebar ul').hide();
+
+ // good
+ $('.sidebar > ul').hide();
+
+ // good
+ $sidebar.find('ul').hide();
+
+ // good (slower)
+ $sidebar.find('ul');
+
+ // good (faster)
+ $($sidebar[0]).find('ul');
+ ```
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## ECMAScript 5 兼容性
+
+
+ - [26.1](#es5-compat--kangax) 参考 [Kangax](https://twitter.com/kangax/) 的 ES5 [兼容性](http://kangax.github.com/es5-compat-table/).
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## ECMAScript 6(ES 2015+)规范
+
+
+ - [27.1](#es6-styles) 以下是链接到 ES6 的各个特性的列表。
+
+1. [Arrow Functions](#arrow-functions)
+1. [Classes](#classes--constructors)
+1. [Object Shorthand](#es6-object-shorthand)
+1. [Object Concise](#es6-object-concise)
+1. [Object Computed Properties](#es6-computed-properties)
+1. [Template Strings](#es6-template-literals)
+1. [Destructuring](#destructuring)
+1. [Default Parameters](#es6-default-parameters)
+1. [Rest](#es6-rest)
+1. [Array Spreads](#es6-array-spreads)
+1. [Let and Const](#references)
+1. [Iterators and Generators](#iterators-and-generators)
+1. [Modules](#modules)
+
+
+ - [27.2](#tc39-proposals) Do not use [TC39 proposals](https://github.com/tc39/proposals) that have not reached stage 3.
+
+ > Why? [They are not finalized](https://tc39.github.io/process-document/), and they are subject to change or to be withdrawn entirely. We want to use JavaScript, and proposals are not JavaScript yet.
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 自动化测试
+
+
+ - [28.1](#testing--yup) 需要吗?**Yup.**
+
+ ```javascript
+ function foo() {
+ return true;
+ }
+ ```
+
+
+ - [28.2](#testing--for-real) **No, but seriously**:
+
+ - Whichever testing framework you use, you should be writing tests!
+ - Strive to write many small pure functions, and minimize where mutations occur.
+ - Be cautious about stubs and mocks - they can make your tests more brittle.
+ - We primarily use [`mocha`](https://www.npmjs.com/package/mocha) at Airbnb. [`tape`](https://www.npmjs.com/package/tape) is also used occasionally for small, separate modules.
+ - 100% test coverage is a good goal to strive for, even if it's not always practical to reach it.
+ - Whenever you fix a bug, _write a regression test_. A bug fixed without a regression test is almost certainly going to break again in the future.
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 性能
+
+ - [On Layout & Web Performance](https://www.kellegous.com/j/2013/01/26/layout-performance/)
+ - [String vs Array Concat](https://jsperf.com/string-vs-array-concat/2)
+ - [Try/Catch Cost In a Loop](https://jsperf.com/try-catch-in-loop-cost)
+ - [Bang Function](https://jsperf.com/bang-function)
+ - [jQuery Find vs Context, Selector](https://jsperf.com/jquery-find-vs-context-sel/13)
+ - [innerHTML vs textContent for script text](https://jsperf.com/innerhtml-vs-textcontent-for-script-text)
+ - [Long String Concatenation](https://jsperf.com/ya-string-concat)
+ - [Are Javascript functions like `map()`, `reduce()`, and `filter()` optimized for traversing arrays?](https://www.quora.com/JavaScript-programming-language-Are-Javascript-functions-like-map-reduce-and-filter-already-optimized-for-traversing-array/answer/Quildreen-Motta)
+ - Loading...
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+
+## 资源
+
+**Learning ES6**
+
+ - [Draft ECMA 2015 (ES6) Spec](https://people.mozilla.org/~jorendorff/es6-draft.html)
+ - [ExploringJS](http://exploringjs.com/)
+ - [ES6 Compatibility Table](https://kangax.github.io/compat-table/es6/)
+ - [Comprehensive Overview of ES6 Features](http://es6-features.org/)
+
+**Read This**
+
+ - [Standard ECMA-262](http://www.ecma-international.org/ecma-262/6.0/index.html)
+ - old [Annotated ECMAScript 5.1](http://es5.github.com/)
+
+**Tools**
+
+ - Code Style Linters
+ + [ESlint](http://eslint.org/) - [Airbnb Style .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc)
+ + [JSHint](http://jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/.jshintrc)
+ + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json)
+
+**Other Style Guides**
+
+ - [Google JavaScript Style Guide](https://google.github.io/styleguide/javascriptguide.xml)
+ - [jQuery Core Style Guidelines](https://contribute.jquery.org/style-guide/js/)
+ - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwaldron/idiomatic.js)
+
+**Other Styles**
+
+ - [Naming this in nested functions](https://gist.github.com/cjohansen/4135065) - Christian Johansen
+ - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen
+ - [Popular JavaScript Coding Conventions on GitHub](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun
+ - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman
+
+**Further Reading**
+
+ - [Understanding JavaScript Closures](https://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll
+ - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer
+ - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz
+ - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban
+ - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock
+
+**Books**
+
+ - [JavaScript: The Good Parts](https://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford
+ - [JavaScript Patterns](https://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov
+ - [Pro JavaScript Design Patterns](https://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz
+ - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](https://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders
+ - [Maintainable JavaScript](https://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas
+ - [JavaScript Web Applications](https://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw
+ - [Pro JavaScript Techniques](https://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig
+ - [Smashing Node.js: JavaScript Everywhere](https://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch
+ - [Secrets of the JavaScript Ninja](https://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault
+ - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg
+ - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
+ - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon
+ - [Third Party JavaScript](https://www.manning.com/books/third-party-javascript) - Ben Vinegar and Anton Kovalyov
+ - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman
+ - [Eloquent JavaScript](http://eloquentjavascript.net/) - Marijn Haverbeke
+ - [You Don't Know JS: ES6 & Beyond](http://shop.oreilly.com/product/0636920033769.do) - Kyle Simpson
+
+**Blogs**
+
+ - [JavaScript Weekly](http://javascriptweekly.com/)
+ - [JavaScript, JavaScript...](https://javascriptweblog.wordpress.com/)
+ - [Bocoup Weblog](https://bocoup.com/weblog)
+ - [Adequately Good](http://www.adequatelygood.com/)
+ - [NCZOnline](https://www.nczonline.net/)
+ - [Perfection Kills](http://perfectionkills.com/)
+ - [Ben Alman](http://benalman.com/)
+ - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/)
+ - [Dustin Diaz](http://dustindiaz.com/)
+ - [nettuts](http://code.tutsplus.com/?s=javascript)
+
+**播客 Podcasts**
+
+ - [JavaScript Air](https://javascriptair.com/)
+ - [JavaScript Jabber](https://devchat.tv/js-jabber/)
+
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 使用人群
+
+ This is a list of organizations that are using this style guide. Send us a pull request and we'll add you to the list.
+
+ - **3blades**: [3Blades/javascript](https://github.com/3blades/javascript)
+ - **4Catalyzer**: [4Catalyzer/javascript](https://github.com/4Catalyzer/javascript)
+ - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript)
+ - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript)
+ - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript)
+ - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript)
+ - **Ascribe**: [ascribe/javascript](https://github.com/ascribe/javascript)
+ - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript)
+ - **Avant**: [avantcredit/javascript](https://github.com/avantcredit/javascript)
+ - **BashPros**: [BashPros/javascript](https://github.com/BashPros/javascript)
+ - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript)
+ - **Bisk**: [bisk/javascript](https://github.com/Bisk/javascript/)
+ - **Blendle**: [blendle/javascript](https://github.com/blendle/javascript)
+ - **Bonhomme**: [bonhommeparis/javascript](https://github.com/bonhommeparis/javascript)
+ - **Brainshark**: [brainshark/javascript](https://github.com/brainshark/javascript)
+ - **Chartboost**: [ChartBoost/javascript-style-guide](https://github.com/ChartBoost/javascript-style-guide)
+ - **ComparaOnline**: [comparaonline/javascript](https://github.com/comparaonline/javascript-style-guide)
+ - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide)
+ - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript)
+ - **DoSomething**: [DoSomething/eslint-config](https://github.com/DoSomething/eslint-config)
+ - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript)
+ - **Ecosia**: [ecosia/javascript](https://github.com/ecosia/javascript)
+ - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide)
+ - **Evolution Gaming**: [evolution-gaming/javascript](https://github.com/evolution-gaming/javascript)
+ - **EvozonJs**: [evozonjs/javascript](https://github.com/evozonjs/javascript)
+ - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript)
+ - **Expensify** [Expensify/Style-Guide](https://github.com/Expensify/Style-Guide/blob/master/javascript.md)
+ - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide)
+ - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript)
+ - **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript)
+ - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style)
+ - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript)
+ - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript-style-guide)
+ - **Huballin**: [huballin/javascript](https://github.com/huballin/javascript)
+ - **HubSpot**: [HubSpot/javascript](https://github.com/HubSpot/javascript)
+ - **Hyper**: [hyperoslo/javascript-playbook](https://github.com/hyperoslo/javascript-playbook/blob/master/style.md)
+ - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide)
+ - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript)
+ - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions)
+ - **JeopardyBot**: [kesne/jeopardy-bot](https://github.com/kesne/jeopardy-bot/blob/master/STYLEGUIDE.md)
+ - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript)
+ - **KickorStick**: [kickorstick/javascript](https://github.com/kickorstick/javascript)
+ - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/Javascript-style-guide)
+ - **Lonely Planet**: [lonelyplanet/javascript](https://github.com/lonelyplanet/javascript)
+ - **M2GEN**: [M2GEN/javascript](https://github.com/M2GEN/javascript)
+ - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript)
+ - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript)
+ - **MitocGroup**: [MitocGroup/javascript](https://github.com/MitocGroup/javascript)
+ - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript)
+ - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript)
+ - **Muber**: [muber/javascript](https://github.com/muber/javascript)
+ - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript)
+ - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript)
+ - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript)
+ - **Nulogy**: [nulogy/javascript](https://github.com/nulogy/javascript)
+ - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript)
+ - **OutBoxSoft**: [OutBoxSoft/javascript](https://github.com/OutBoxSoft/javascript)
+ - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript)
+ - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide)
+ - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript)
+ - **React**: [facebook.github.io/react/contributing/how-to-contribute.html#style-guide](https://facebook.github.io/react/contributing/how-to-contribute.html#style-guide)
+ - **REI**: [reidev/js-style-guide](https://github.com/rei/code-style-guides/blob/master/docs/javascript.md)
+ - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide)
+ - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide)
+ - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript)
+ - **Springload**: [springload/javascript](https://github.com/springload/javascript)
+ - **StratoDem Analytics**: [stratodem/javascript](https://github.com/stratodem/javascript)
+ - **SteelKiwi Development**: [steelkiwi/javascript](https://github.com/steelkiwi/javascript)
+ - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/guide-javascript)
+ - **SwoopApp**: [swoopapp/javascript](https://github.com/swoopapp/javascript)
+ - **SysGarage**: [sysgarage/javascript-style-guide](https://github.com/sysgarage/javascript-style-guide)
+ - **Syzygy Warsaw**: [syzygypl/javascript](https://github.com/syzygypl/javascript)
+ - **Target**: [target/javascript](https://github.com/target/javascript)
+ - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript)
+ - **The Nerdery**: [thenerdery/javascript-standards](https://github.com/thenerdery/javascript-standards)
+ - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript)
+ - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide)
+ - **WeBox Studio**: [weboxstudio/javascript](https://github.com/weboxstudio/javascript)
+ - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript)
+ - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript)
+ - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript)
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 翻译
+
+ This style guide is also available in other languages:
+
+ -  **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide)
+ -  **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript)
+ -  **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide)
+ -  **Chinese (Simplified)**: [sivan/javascript-style-guide](https://github.com/sivan/javascript-style-guide)
+ -  **Chinese (Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript)
+ -  **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide)
+ -  **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide)
+ -  **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide)
+ -  **Japanese**: [mitsuruog/javascript-style-guide](https://github.com/mitsuruog/javascript-style-guide)
+ -  **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide)
+ -  **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript)
+ -  **Russian**: [uprock/javascript](https://github.com/uprock/javascript)
+ -  **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide)
+ -  **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide)
+ -  **Vietnam**: [giangpii/javascript-style-guide](https://github.com/giangpii/javascript-style-guide)
+
+
+## JavaScript 编码规范说明
+
+ - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide)
+
+
+## 一起来讨论 JavaScript
+
+ - Find us on [gitter](https://gitter.im/airbnb/javascript).
+
+
+## 贡献者 Contributors
+
+ - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors)
+
+
+## 许可 License
+
+(The MIT License)
+
+Copyright (c) 2014-2017 Airbnb
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**[⬆ 返回目录](#table-of-contents)**
+
+
+## 修正案 Amendments
+
+We encourage you to fork this guide and change the rules to fit your team's style guide. Below, you may list some amendments to the style guide. This allows you to periodically update your style guide without having to deal with merge conflicts.
+
+# };
diff --git a/docs/js-in-html.html b/docs/js-in-html.html
new file mode 100644
index 0000000000..2941228b9c
--- /dev/null
+++ b/docs/js-in-html.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+微信授权
+
+
+
+
+
+
diff --git a/docs/rules.md b/docs/rules.md
new file mode 100644
index 0000000000..6768069f0f
--- /dev/null
+++ b/docs/rules.md
@@ -0,0 +1,135 @@
+
+JS 代码规范,使用 ESLint,
+
+代码规范已转移,参见[javascript-style-guide](https://github.com/webcoding/javascript-style-guide)
+
+CSS/SCSS 代码规范,详见 [css-style-guide](https://github.com/webcoding/css-style-guide)
+
+
+## JavaScript Standard Style
+
+本代码规范描述,来自[JS书写规范](http://standardjs.com/rules.html)
+
+- 使用2个空格缩进
+- 字符串单、双引号('', ""),避免使用转义。
+- 不存在未使用的变量
+- 在关键字后添加一个空格
+- 在函数声明的括号之前添加一个空格
+- 始终使用 === 代替 ==
+- 中间操作必须间隔 如 var message = 'hello, ' + name + '!'
+- 逗号后应该有一个空格
+- 保持else语句和 大括号{} 在同一行
+- 对于多行 if 语句,使用大括号 {}
+- 总是处理 err 函数参数
+- 浏览器环境始终保留全局变量前缀(window.), document,console和navigator 例外
+- 不允许多个空白行 ???多行空白可用来适当划分代码功能区域块
+- 三元运算符,如要多行,操作符放置在行首
+- 单 var 声明,每个变量声明都使用 var 独立成行 ???
+- 条件赋值附加在圆括号内,代表故意赋值,如 if ((m = text.match(expr))) { //... }
+- 在单行块内添加空格,如 function foo () { return true }
+- 变量及函数命名使用 camelcase 小驼峰格式
+- 尾逗号不允许 ???改为单行尾逗号不允许,多行必尾逗号须有
+- 逗号必须放在当前行的末尾
+- 点操作符要与属性在同一行
+- 文件末尾必须有一个空行(保存时自动插入)
+- 函数标识符与调用之间不能有空白 console.log('hello')
+- 键值对的冒号: 右侧和值之间必须有空格,左侧则无空格
+- 构造函数命名必须大写字母开头 function Animal () {}
+- 无参数的构造函数必须用括号调用 var dog = new Animal()
+- 对象定义了 setter,则必须包含 getter 来获取其值
+- 派生类的构造函数必须调用 super()
+- 使用数组常量代替数组构造器
+- 避免使用arguments.callee和arguments.caller
+- 避免修改变量类型
+- 避免修改使用const变量
+- 避免在条件下使用常量表达式(循环除外)
+- 正则表达式中不能有控制字符 var pattern = /\x1f/ // ✗ avoid
+- 不能有 debugger 语句
+- 不能使用 delete 操作符作用域变量
+- 函数定义中不能有重复的参数
+- 类成员中属性名不能重复
+- 对象的 key 不能重复
+- switch 语句不能有重复的 case 标识
+- 一个模块使用一个 import 导入语句 import { myFunc1, myFunc2 } from 'module' √
+- 正则表达式中不能有空字符类 /124[]/ // ✗ avoid
+- 不能使用空的解构模式 const { a: {} } = foo // ✗ avoid
+- 不要使用 eval() 函数
+- 不能对 catch 参数重新赋值
+- 不能扩展原生对象 如 Object.prototype.age = 21 // ✗ avoid
+- 避免不必要的函数绑定
+- 避免不要要的 Boolean 类型,如 !!result // ✗ avoid
+- 函数表达式去掉不必要的圆括号包裹 const myFunc = (function () { }) // ✗ avoid
+- switch 使用 break 来避免贯通流程
+- 不可省略小数前面的零 如 0.5
+- 避免函数声明再赋值
+- 不能对只读变量赋值 如 window = {} // ✗ avoid
+- 不能使用隐形 eval() setTimeout("alert('Hello world')") // ✗ avoid
+- 嵌套块中不能做函数声明,如 if 的大括号中
+- 不使用无效的正则表达式字符串用于正则构造函数
+- 不使用无规则空白
+- 不使用 __iterator__ 属性
+- 不使用与作用域变量同名的属性名称
+- 不使用 label 语句
+- 不使用没必要的嵌套块
+- 避免空格和制表符混合缩进
+- 除了缩进,不要使用多个空格
+- 不使用多行字符串
+- 构造函数创建实例,必须有变量引用
+- 不使用 Function 做构造函数
+- 不使用 Object 做构造函数
+- 不使用 new require 做构造函数
+- 不使用 Symbol 做构造函数
+- 不使用原始包装实例 const message = new String('hello') // ✗ avoid
+- 不对全局变量做赋值调用 const math = Math() // ✗ avoid
+- 不使用八进制常量
+- 在字符串中不使用八进制转义序列 const copyright = 'Copyright \251' // ✗ avoid
+- 字符串串联使用时,避免直接使用__filename 和 __dirname const pathToFile = __dirname + '/app.js' // ✗ avoid
+- 避免使用__proto__,可以使用 getPrototypeOf 替代
+- 变量不能重复声明
+- 避免在正则表达式文本多重空间
+- return 返回赋值表达式,需要用圆括号包裹
+- 避免将变量赋值给自己
+- 避免变量同自己比较
+- 避免使用逗号运算符
+- 受限制名称(如 undefined)不要使用做变量
+- tab 不应该被使用
+- 普通字符串不能包含占位符文字 const message = 'Hello ${name}' // ✗ avoid
+- super() 调用前,不要使用 this. 去操作
+- 错误抛出要使用错误对象包裹
+- 行尾不允许空白(自动删除)
+- undefined 不允许用来赋值
+- 未修改值不能做循环条件
+- 使用简单逻辑运算替代不必要的三元运算符 val ? val : 0 ==》 val || 0
+- return, throw, continue, 和 break 后不要再有语句,否则无法执行
+- 在finally语句块中不能有 return 等流控制语句
+- 关系运算符的左操作数不能是否定的 if (!key in obj) {} // ✗ avoid
+- 避免不必要的使用 call() 和 apply(), sum.call(null, 1, 2, 3) // ✗ avoid
+- 避免在对象上做不必要的属性计算 const user = { ['name']: 'John Doe' } // ✗ avoid
+- 不要使用多余的构造函数
+- 不要使用非必要的转义
+- import, export, and destructured 上不要同名称去重命名 import { config as config } from './config' // ✗ avoid
+- 属性前不要有空格
+- 不要使用 with 语句
+- 保持对象属性换行的一致性
+- 块语句内不要空白填充
+- 扩展运算符后不要空格 fn(... args) // ✗ avoid
+- 分号后必须要有空格,前面则不要空格
+- 块语句前必须有个空格 if (admin){...} // ✗ avoid
+- 括号内相邻位置不要空格 getName( name ) // ✗ avoid
+- 一元运算符后必须有个空格 typof !admin // ✓ ok
+- 注释// 后必须要有个空格
+- 模板字符串中没有空格 const message = `Hello, ${ name }` // ✗ avoid
+- 使用 isNaN() 来检测 NaN 类型 if (isNaN(price)) { } // ✓ ok
+- typeof 必须与有效字符串类型比较
+- !!!立即调用函数表达式(IFFE)必须包括在圆括号内 const getName = (function () { }) // ✓ ok
+- yield * 运算中, * 前后都必须有空格 yield * increment() // ✓ ok
+- 避免 yoda 的条件 if (42 === age) { } // ✗ avoid
+
+关于分号:
+
+- !!!行尾不要分号
+- 永远不要使用 (, [, or ` 起行,JavaScript 中的“自动分号插入”机制(ASI)会有问题,在!!!设定的规则下
+
+在以 ([/+- 开头的语句前加分号(由于正常写法均不会出现以 .,*% 作为语句开头,因此只需记住前面5个即可,你看能懒则懒哦)
+详细参见 https://github.com/feross/standard/blob/master/RULES.md#helpful-reading
+
diff --git a/docs/test.vue b/docs/test.vue
new file mode 100644
index 0000000000..1dda528e67
--- /dev/null
+++ b/docs/test.vue
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
diff --git a/linters/.eslintrc.js b/linters/.eslintrc.js
new file mode 100644
index 0000000000..9d090b60c6
--- /dev/null
+++ b/linters/.eslintrc.js
@@ -0,0 +1,869 @@
+
+
+// 此文件为设置参考
+// 所有 ESLint 属性有列表设定,以及为什么
+
+
+/* global aa */
+// http://eslint.org/docs/rules/no-undef
+
+/**
+ * 参看文档
+ * https://github.com/feross/eslint-config-standard/blob/master/eslintrc.json
+ *
+ * https://segmentfault.com/a/1190000004468428
+ * http://www.tuicool.com/articles/rIFBfey
+ * http://blog.csdn.net/helpzp2008/article/details/51507428
+ * http://www.cnblogs.com/allin123/p/5754500.html
+ */
+
+
+//文件中关闭验证
+
+/*eslint-disable */
+
+//suppress all warnings between comments
+//alert("foo");
+
+/*eslint-enable */
+
+
+
+//文件中指定规则不验证
+
+/*eslint-disable no-alert, no-console */
+
+// alert("foo");
+// console.log("bar");
+
+/*eslint-enable no-alert */
+
+
+module.exports = {
+ // http://eslint.org/docs/user-guide/configuring
+ // 环境定义了预定义的全局变量, 更多在官网查看
+ "env": {
+ "browser": true,
+ "node": true,
+ "commonjs": true,
+ "amd": true,
+ "es6": true,
+ "mocha": true,
+ },
+
+ // 声明全局变量。值 false 表示不可写(只读属性),true 表示可写
+ // 无论 true 或 false,都代表声明了
+ // 也可以文件中声明,如下
+ // /* global var1, var2 */
+ // /* global var1:false, var2:false */
+ "globals": {
+ "_": false,
+ "$": false,
+ "define": false,
+ "document": false,
+ "navigator": false,
+ "window": false,
+ },
+
+ //表示使用默认的规则进行校验
+ // "extends": "eslint:recommended",
+ // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
+ // https://github.com/feross/eslint-config-standard/blob/master/eslintrc.json
+ "extends": "standard",
+
+ // required to lint *.vue files
+ // eslint-config-standard
+ // 可共享的标准格式配置, 在自己工程中,加入 .eslint 文件即可
+ // eslint-plugin-html
+ // 支持从 html 等文件的