JavaScript最合理的方法 A mostly reasonable approach to JavaScript

Other Style Guides
- Types
- References
- Objects
- Arrays
- Destructuring
- Strings
- Functions
- Arrow Functions
- Classes & Constructors
- Modules
- Iterators and Generators
- Properties
- Variables
- Hoisting
- Comparison Operators & Equality
- Blocks
- Comments
- Whitespace
- Commas
- Semicolons
- Type Casting & Coercion
- Naming Conventions
- Accessors
- Events
- jQuery
- ECMAScript 5 Compatibility
- ECMAScript 6+ (ES 2015+) Styles
- Testing
- Performance
- Resources
- In the Wild
- Translation
- The JavaScript Style Guide Guide
- Chat With Us About JavaScript
- Contributors
- License
-
1.1 原始值: 相当于传值
string
number
boolean
null
undefined
const foo = 1; let bar = foo; bar = 9; console.log(foo, bar); // => 1, 9
-
1.2 复杂类型: 相当于传引用
object
array
function
const foo = [1, 2]; const bar = foo; bar[0] = 9; console.log(foo[0], bar[0]); // => 9, 9
-
2.1 所有的赋值都用
const
,避免使用var
. eslint:prefer-const
,no-const-assign
因为这个确保你不会改变你的初始值,重复引用会导致bug和代码难以理解
// bad var a = 1; var b = 2; // good const a = 1; const b = 2;
-
2.2 如果你一定要对参数重新赋值,那就用
let
,而不是var
. eslint:no-var
jscs:disallowVar
因为
let
是块级作用域,而var
是函数级作用域// bad var count = 1; if (true) { count += 1; } // good, use the let. let count = 1; if (true) { count += 1; }
-
2.3 注意:
let
、const
都是块级作用域// const and let only exist in the blocks they are defined in. { let a = 1; const b = 1; } console.log(a); // ReferenceError console.log(b); // ReferenceError
-
3.1 - 使用字面值创建对象. eslint:
no-new-object
// bad const item = new Object(); // good const item = {};
-
3.2 当创建一个带有动态属性名的对象时,用计算后属性名
为什么? 这可以使你将定义的所有属性放在对象的一个地方.
function getKey(k) { return `a key named ${k}`; } // bad const obj = { id: 5, name: 'San Francisco', }; obj[getKey('enabled')] = true; // good getKey('enabled')是动态属性名 const obj = { id: 5, name: 'San Francisco', [getKey('enabled')]: true, };
-
3.3 用对象方法简写. eslint:
object-shorthand
jscs:requireEnhancedObjectLiterals
// 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 用属性值缩写. eslint:
object-shorthand
jscs:requireEnhancedObjectLiterals
这样写的更少且更可读
const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { lukeSkywalker: lukeSkywalker, }; // good const obj = { lukeSkywalker, };
-
3.5 将你的所有缩写放在对象声明的开始.
这样也是为了更方便的知道有哪些属性用了缩写.
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 只对那些无效的标示使用引号
''
. eslint:quote-props
jscs:disallowQuotedKeysInObjects
Why? 通常我们认为这种方式主观上易读。他提升了代码高亮,并且页更容易被许多JS引擎压缩。
// bad
const bad = {
'foo': 3,
'bar': 4,
'data-blah': 5,
};
// good
const good = {
foo: 3,
bar: 4,
'data-blah': 5,
};
- 3.7 不要直接调用
Object.prototype
这个方法,如hasOwnProperty
,propertyIsEnumerable
,isPrototypeOf
。
Why? 这些方法可能是挂在一个有问题的对象的属性上 - 如:
{ hasOwnProperty: false }
- 或这是一个空对象Object.create(null)
// 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 涉及到对象拷贝
Object.assign
时,用对象的扩展运算符去拿到一个带有真是属性的新对象(而不是只是拿到了旧的对象的引用)
// 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 es6扩展运算符 ...
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 }
-
4.1 用字面量赋值。 eslint:
no-array-constructor
// bad const items = new Array(); // good const items = [];
-
4.2 用Array#push 代替直接向数组中添加一个值。
const someStack = []; // bad someStack[someStack.length] = 'abracadabra'; // good someStack.push('abracadabra');
-
4.3 用数组的解构赋值
...
去赋值数组// bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i += 1) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];
-
4.4 用Array.from将一个类数组的对象转换成数组.
const foo = document.querySelectorAll('.foo'); const nodes = Array.from(foo);
-
4.5 在数组方法的回调函数中使用renturn语句。如果函数只有一个语句就可以忽略不用8.2. eslint:
array-callback-return
// 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; });
-
5.1 当需要获取并多次使用对象的属性时用对象的解构。 jscs:
requireObjectDestructuring
Why? 解构保存了这些属性的临时引用
// 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 用数组解构. jscs:
requireArrayDestructuring
const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr;
-
5.3 多个返回值用对象的解构,而不是数据解构。 jscs:
disallowArrayDestructuringReturn
Why? 你可以在之后添加新的属性或者变换变量的顺序而不会打破原有的调用
// bad function processInput(input) { // then a miracle occurs return [left, right, top, bottom]; } // the caller needs to think about the order of return data const [left, __, top] = processInput(input); // good function processInput(input) { // then a miracle occurs return { left, right, top, bottom }; } // the caller selects only the data they need const { left, top } = processInput(input);
-
6.1 对string用单引号
''
。 eslint:quotes
jscs:validateQuoteMarks
// bad const name = "Capt. Janeway"; // bad - 样例应该包含插入文字或换行 const name = `Capt. Janeway`; // good const name = 'Capt. Janeway';
-
6.2 超过100个字符的字符串不应该用string串联成多行
Why? 被折断的字符串工作起来是糟糕的而且使得代码更不易被搜索
// 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 当程序化组织字符串时,使用模板而不是串联。 eslint:
prefer-template
template-curly-spacing
jscs:requireTemplateStrings
Why? 模板字符串更具可读性、语法简洁、字符串插入参数。
// 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 永远不要在字符串中用
eval()
,他就是潘多拉盒子
-
6.5 不要使用不必要的转义字符。eslint:
no-useless-escape
Why? 反斜线可读性差,所以他们只在必须使用时才出现
// bad const foo = '\'this\' \i\s \"quoted\"'; // good const foo = '\'this\' is "quoted"'; //best const foo = `my name is '${name}'`;
-
7.1 用命名函数表达式而不是函数声明。eslint:
func-style
jscs:disallowFunctionDeclarations
函数表达式: const func = function () {}
函数声明: function func() {}
Why? 函数声明式作用域被提前了,这意味着在一个文件里函数很容易(太容易了)在其定义之前被引用。这样伤害了代码可读性和可维护性。如果你发现一个函数有大又复杂,这个函数妨碍这个文件其他部分的理解性,这可能就是时候把这个函数单独抽成一个模块了。别忘了给表达式命名——匿名函数会在错误调用栈里难以定位。 (Discussion)
// bad function foo() { // ... } // bad const foo = function () { // ... }; // good, 函数表达式也需要命名 const foo = function bar() { // ... };
- 7.2 把立即执行函数包裹在圆括号里。 eslint:
wrap-iife
jscs:requireParenthesesAroundIIFE
immediately invoked function expression = IIFE Why?一个立即调用的函数表达式是一个单一的单元 - 把它和他的调用者(圆括号)包裹起来,在括号中,干净地表达这一点。[An immediately invoked function expression is a single unit - wrapping both it, and its invocation parens, in parens, cleanly expresses this. google翻译, 暂不知道想表达什么] 。 注意:在模块化引用里,不需要使用IIFE
// immediately-invoked function expression (IIFE) (function () { console.log('Welcome to the Internet. Please follow me.'); }());
- 7.3 不要在非函数块(if、while等等)内声明函数。把这个函数分配给一个变量。浏览器会允许你这样做,但浏览器解析方式不同,这是一个坏消息。【详见
no-loop-func
】 eslint:no-loop-func
-
7.4 Note: ECMA-262 定义一个
block
有一系列语句,函数声明不是语句。 [暂不理解: ECMA-262 defines ablock
as a list of statements. A function declaration is not a statement.]Read ECMA-262's note on this issue.// bad if (currentUser) { function test() { console.log('Nope.'); } } // good let test; if (currentUser) { test = () => { console.log('Yup.'); }; }
-
7.5 不要用
arguments
命名参数。他的优先级高于每个函数作用域自带的arguments
对象// bad function foo(name, options, arguments) { // ... } // good function foo(name, options, args) { // ... }
-
7.6 不要使用
arguments
,用rest语法...
代替。 eslint:prefer-rest-params
Why?
...
明确你想用那个参数。而且rest参数是真数组,而不是类似数组的arguments
// bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good function concatenateAll(...args) { return args.join(''); }
-
7.7 用默认参数而不是在函数里对参数重新赋值。
// really bad function handleThings(opts) { // No! We shouldn't mutate function arguments. // Double bad: if opts is falsy it'll be set to an object which may // be what you want but it can introduce subtle bugs. opts = opts || {}; // ... } // still bad function handleThings(opts) { if (opts === void 0) { opts = {}; } // ... } // good function handleThings(opts = {}) { // ... }
-
7.8 默认参数避免副作用
Why? 他会导致参数混乱
var b = 1; // bad function count(a = b++) { console.log(a); } count(); // 1 count(); // 2 count(3); // 3 count(); // 3
-
7.9 把默认参数赋值放在最后
// bad function handleThings(opts = {}, name) { // ... } // good function handleThings(name, opts = {}) { // ... }
-
7.10 不要用函数构造器创建函数。 eslint:
no-new-func
Why? 以这种方式创建函数将类似于eval()来计算字符串,这会打开漏洞。
// bad var add = new Function('a', 'b', 'return a + b'); // still bad var subtract = Function('a', 'b', 'return a - b');
-
7.11 函数签名部分要有空格。eslint:
space-before-function-paren
space-before-blocks
Why? 统一性好,而且在你添加/删除一个名字的时候不需要添加/删除空格
// bad const f = function(){}; const g = function (){}; const h = function() {}; // good const x = function () {}; const y = function a() {};
-
7.12 不要改参数的数据结构. eslint:
no-param-reassign
Why? 操作参数对象对原始调用者会导致意想不到的副作用。 就是不要改参数的数据结构,保留参数原始值和数据结构。
// bad function f1(obj) { obj.key = 1; }; // good function f2(obj) { const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1; };
-
7.13 不要重新分配参数。 eslint:
no-param-reassign
Why? 重新分配参数会导致意外行为,尤其当参数是object的时候。这也会导致压缩问题,特别是在V8里
// 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 用
spread
操作符...
去调用多变的函数更好。 eslint:prefer-spread
Why? 这样更清晰,你不必提供上下文,而且你不能轻易地用
apply
来组成new
// 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 包含多行多行签名的函数或调用应该缩进, 就像这里其他的每一个多行列表: 每行与上一行对齐并用逗号结尾
// bad function foo(bar, baz, quux) { // ... } // good 缩进不要太过分 function foo( bar, baz, quux, ) { // ... } // bad console.log(foo, bar, baz); // good console.log( foo, bar, baz, );
-
8.1 当你一定要用函数表达式(当传递匿名函数时)的时候就用箭头表达式吧。 eslint:
prefer-arrow-callback
,arrow-spacing
jscs:requireArrowFunctions
Why? 他创建了一个
this
的当前执行上下文的函数的版本,这通常就是你想要的;而且箭头函数是更简洁的语法Why not? 如果你有一个相当复杂的函数,你可能会把这个逻辑移出到他自己的函数声明里 【不甚理解】
// 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 如果函数体有一个表达式组成,删除大括号和return。否则,继续用大括号和
return
语句。 eslint:arrow-parens
,arrow-body-style
jscs:disallowParenthesesAroundArrowParam
,requireShorthandArrowFunctions
Why? 语法糖,当多个函数链在一起的时候好读
// 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 万一表达式涉及多行,把他包裹在圆括号里更可读。
Why? 这样清晰的显示函数的开始和结束
// 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 如果你的函数有一个参数并且没有大括号,就删除圆括号。否则,参数总是放在圆括号里。 eslint:
arrow-parens
jscs:disallowParenthesesAroundArrowParam
Why? Less visual clutter.
// bad [1, 2, 3].map((x) => x * x); // good [1, 2, 3].map(x => x * x); // 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 避免箭头函数(
=>
)和比较操作符(<=, >=
)混淆. eslint:no-confusing-arrow
// 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; };
-
9.1 常用
class
,避免直接操作prototype
Why?
class
语法更简洁更易理解// 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 用
extends
实现继承Why? 它是一种内置的方法来继承原型功能而不打破
instanceof
// bad const inherits = require('inherits'); function PeekableQueue(contents) { Queue.apply(this, contents); } inherits(PeekableQueue, Queue); PeekableQueue.prototype.peek = function () { return this._queue[0]; } // good class PeekableQueue extends Queue { peek() { return this._queue[0]; } }
-
9.3 方法可以返回
this
来实现方法链// 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 写一个定制的toString()方法是可以的,只要保证它是可以正常工作且没有副作用的
class Jedi { constructor(options = {}) { this.name = options.name || 'no name'; } getName() { return this.name; } toString() { return `Jedi - ${this.getName()}`; } }
-
9.5 如果没有具体说明,类有默认的构造方法。一个空的构造函数或只是继承父类的构造函数是不需要写的。 eslint:
no-useless-constructor
// 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 避免重复类成员。 eslint:
no-dupe-class-members
Why? 重复类成员会默默的执行最后一个 —— 重复本身也是一个bug
// bad class Foo { bar() { return 1; } bar() { return 2; } } // good class Foo { bar() { return 1; } } // good class Foo { bar() { return 2; } }
-
10.1 用(
import
/export
) 模块而不是无标准的模块系统。你可以随时转到你喜欢的模块系统。Why? 模块化是未来,让我们现在就开启未来吧。
// 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 不要用通配符import
Why? 这确保你有单个默认的导出
// bad import * as AirbnbStyleGuide from './AirbnbStyleGuide'; // good import AirbnbStyleGuide from './AirbnbStyleGuide';
-
10.3 不要直接从import中直接export
Why? 虽然一行是简洁的,有一个明确的方式进口和一个明确的出口方式使事情一致。
// bad // filename es6.js export { es6 as default } from './AirbnbStyleGuide'; // good // filename es6.js import { es6 } from './AirbnbStyleGuide'; export default es6;
-
10.4 Only import from a path in one place. eslint:
no-duplicate-imports
Why? 从同一个路径下import多行会使代码难以维护
// bad import foo from 'foo'; // … some other imports … // import { named1, named2 } from 'foo'; // good import foo, { named1, named2 } from 'foo'; // good import foo, { named1, named2, } from 'foo';
-
10.5 不要到处可变的东西 eslint:
import/no-mutable-exports
Why? 总的来说变化都是需要避免的,特别是输出可变的绑定。虽然在某些场景下可能需要这种基础,但总的来说应该到处常量
// bad let foo = 3; export { foo } // good const foo = 3; export { foo }
-
10.6 在一个单一导出模块里,用
export default
更好 eslint:import/prefer-default-export
// bad export function foo() {} // good export default function foo() {}
-
10.7
import
放在其他所有语句之前。 eslint:import/first
Why? 让
import
放在最前面防止意外行为。// bad import foo from 'foo'; foo.init(); import bar from 'bar'; // good import foo from 'foo'; import bar from 'bar'; foo.init();
-
10.8 多行import应该缩进,就像多行数组和对象字面量
Why? 花括号与样式指南中每个其他花括号块遵循相同的缩进规则,逗号也是。
// bad import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path'; // good import { longNameA, longNameB, longNameC, longNameD, longNameE, } from 'path';
-
10.9 在import语句里不允许Webpack loader语法 eslint:
import/no-webpack-loader-syntax
Why? 一旦用Webpack语法在import里会把代码耦合到模块绑定器。最好是在
webpack.config.js
里写webpack loader语法// 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';
-
11.1 不要用遍历器。用JavaScript高级函数代替
for-in
、for-of
。 eslint:no-iterator
no-restricted-syntax
Why? 这加强我们的不可变规则。 处理返回值的纯函数比副作用更容易推理。
Use
map()
/every()
/filter()
/find()
/findIndex()
/reduce()
/some()
/ ... to iterate over arrays, andObject.keys()
/Object.values()
/Object.entries()
to produce arrays so you can iterate over objects.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 现在不要用generator
Why? 它在es5上支持的不好
-
11.3 如果你一定要用,或者你忽略我们的建议, 请确保它们的函数签名空格是得当的。 eslint:
generator-star-spacing
Why?
function
和*
是同一概念关键字 -*
不是function
的修饰符,function*
是一个和function
不一样的独特结构// 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* () { // ... }
-
12.1 访问属性时使用点符号. eslint:
dot-notation
jscs:requireDotNotation
const luke = { jedi: true, age: 28, }; // bad const isJedi = luke['jedi']; // good const isJedi = luke.jedi;
-
12.2 当获取的属性是变量时用方括号
[]
取const luke = { jedi: true, age: 28, }; function getProp(prop) { return luke[prop]; } const isJedi = getProp('jedi');
-
13.1 用
const
声明变量。不这样做会导致全局变量。 我们想要避免污染全局命名空间。首长这样警告我们。 eslint:no-undef
prefer-const
// bad superPower = new SuperPower(); // good const superPower = new SuperPower();
-
13.2 声明一个变量用一个
const
。 eslint:one-var
jscs:disallowMultipleVarDecl
Why? 这种方式很容易去声明新的变量,你不用去考虑把
;
调换成,
,或者引入一个只有标点的不同的变化。这种做法也可以是你在调试的时候单步每个声明语句,而不是一下跳过所有声明。// 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
const
放一起,let
放一起Why? 在你需要分配一个新的变量, 而这个变量依赖之前分配过的变量的时候,这种做法是有帮助的
// 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 在你需要的地方声明变量,但是要放在合理的位置
Why?
let
和const
都是块级作用域而不是函数级作用域// 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 不要使用链接变量分配
Why? 链接变量分配创建隐式全局变量。
// 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 不要使用一元自增自减运算符(++, --). eslint
no-plusplus
Why? 根据eslint文档,一元增量和减量语句受到自动分号插入的影响,并且可能会导致应用程序中的值递增或递减的无声错误。 使用
num + = 1
而不是num ++
或num ++
语句来表达你的值也是更有表现力的。 禁止一元增量和减量语句还会阻止您无意地预增/预减值,这也会导致程序出现意外行为。// 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;
-
14.1
var
声明会被提前到他的作用域的最前面,它分配的值还没有提前。const
和let
被赋予了新的调用概念时效区 —— Temporal Dead Zones (TDZ)。 重要的是要知道为什么 typeof不再安全.// 我们知道这个不会工作,假设没有定义全局的notDefined function example() { console.log(notDefined); // => throws a ReferenceError } // 在你引用的地方之后声明一个变量,他会正常输出是因为变量作用域上升。 // 注意: declaredButNotAssigned的值没有上升 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 匿名函数表达式和
var
情况相同function example() { console.log(anonymous); // => undefined anonymous(); // => TypeError anonymous is not a function var anonymous = function () { console.log('anonymous function expression'); }; }
-
14.3 已命名函数表达式提升他的变量名,不是函数名或函数体
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'); }; }
-
14.4 函数声明则提升了函数名和函数体
function example() { superPower(); // => Flying function superPower() { console.log('Flying'); } }
-
15.2 条件语句如'if'语句使用强制`ToBoolean'抽象方法来评估它们的表达式,并且始终遵循以下简单规则:
- Objects 计算成 true
- Undefined 计算成 false
- Null 计算成 false
- Booleans 计算成 the value of the boolean
- Numbers
- +0, -0, or NaN 计算成 false
- 其他 true
- Strings
''
计算成 false- 其他 true
if ([0] && []) { // true // 数组(即使是空数组)是对象,对象会计算成true }
-
15.3 布尔值用缩写,而字符串和数字要明确比较对象
// bad if (isValid === true) { // ... } // good if (isValid) { // ... } // bad if (name) { // ... } // good if (name !== '') { // ... } // bad if (collection.length) { // ... } // good if (collection.length > 0) { // ... }
- 15.4 更多信息请见Angus Croll的真理、平等和JavaScript —— Truth Equality and JavaScript
- 15.5 在
case
和default
分句里用大括号创建一块包含语法声明的区域(e.g.let
,const
,function
, andclass
).
Why? 语法声明在整个
switch
的代码块里都可见,但是只有当其被分配后才会初始化,他的初始化时当这个case
被执行时才产生。 当多个case
分句试图定义同一个事情时就出问题了
eslint rules: no-case-declarations
.
```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 三元表达式不应该嵌套,通常是单行表达式。
eslint rules:
no-nested-ternary
.// 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 避免不需要的三元表达式
eslint rules:
no-unneeded-ternary
.// 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;
-
16.1 用大括号包裹多行代码块
// 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
if
表达式的else
和if
的关闭大括号在一行。 eslint:brace-style
jscs:disallowNewlineBeforeBlockStatements
// bad if (test) { thing1(); thing2(); } else { thing3(); } // good if (test) { thing1(); thing2(); } else { thing3(); }
-
17.1 多行注释用
/** ... */
// 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 */ function make(tag) { // ... return element; }
-
17.2 单行注释用
//
,将单行注释放在被注释区域上面。如果注释不是在第一行,那么注释前面就空一行// 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 所有注释开头空一个,方便阅读。 eslint:
spaced-comment
// 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 在你的注释前使用
FIXME'或
TODO'前缀, 这有助于其他开发人员快速理解你指出的需要重新访问的问题, 或者您建议需要实现的问题的解决方案。 这些不同于常规注释,因为它们是可操作的。 动作是FIXME: - 需要计算出来
或TODO: - 需要实现
。
-
17.5 用
// FIXME:
给问题做注释class Calculator extends Abacus { constructor() { super(); // FIXME: shouldn't use a global here total = 0; } }
-
17.6 用
// TODO:
去注释问题的解决方案class Calculator extends Abacus { constructor() { super(); // TODO: total should be configurable by an options param this.total = 0; } }
-
18.1 tab空两格. eslint:
indent
jscs:validateIndentation
// bad function foo() { ∙∙∙∙const name; } // bad function bar() { ∙const name; } // good function baz() { ∙∙const name; }
-
18.2 在大括号前空一格。 eslint:
space-before-blocks
jscs:requireSpaceBeforeBlockStatements
// 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 在控制语句(
if
,while
etc.)的圆括号前空一格。在函数调用和定义时,参数列表和函数名之间不空格。 eslint:keyword-spacing
jscs:requireSpaceAfterKeywords
// bad if(isJedi) { fight (); } // good if (isJedi) { fight(); } // bad function fight () { console.log ('Swooosh!'); } // good function fight() { console.log('Swooosh!'); }
-
18.4 用空格来隔开运算符。 eslint:
space-infix-ops
jscs:requireSpaceBeforeBinaryOperators
,requireSpaceAfterBinaryOperators
// bad const x=y+5; // good const x = y + 5;
-
18.5 文件结尾空一行. eslint:
eol-last
// bad import { es6 } from './AirbnbStyleGuide'; // ... export default es6;
// bad import { es6 } from './AirbnbStyleGuide'; // ... export default es6;↵ ↵
// good import { es6 } from './AirbnbStyleGuide'; // ... export default es6;↵
-
18.6 当出现长的方法链(>2个)时用缩进。使用前导点 强调该行是一个方法调用,而不是一个新的语句。eslint:
newline-per-chained-call
no-whitespace-before-property
// 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 在一个代码块后下一条语句前空一行。 jscs:
requirePaddingNewLinesAfterBlocks
// 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 不要用空白行填充块。 eslint:
padded-blocks
jscs:disallowPaddingNewlinesInBlocks
// 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 圆括号里不要加空格。 eslint:
space-in-parens
jscs:disallowSpacesInsideParentheses
// 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 方括号里不要加空格。 eslint:
array-bracket-spacing
jscs:disallowSpacesInsideArrayBrackets
// bad const foo = [ 1, 2, 3 ]; console.log(foo[ 0 ]); // good, 逗号分隔符还是要空格的 const foo = [1, 2, 3]; console.log(foo[0]);
-
18.11 花括号里加空格。 eslint:
object-curly-spacing
jscs:requireSpacesInsideObjectBrackets
// bad const foo = {clark: 'kent'}; // good const foo = { clark: 'kent' };
-
18.12 避免一行代码超过100个字符(包含空格)。
-
注意: 对于上面——strings--line-length,长字符串不受此规则限制,不应分解。 eslint:
max-len
jscs:maximumLineLength
Why? 这样确保可读性和可维护性
// 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.'));
-
19.1 前置逗号: 不 eslint:
comma-style
jscs:requireCommaBeforeLineBreak
// 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 额外结尾逗号: 要 eslint:
comma-dangle
jscs:requireTrailingComma
Why? 这导致git diffs更清洁。 此外,像Babel这样的转换器会删除转换代码中的额外的逗号,这意味着你不必担心旧版浏览器中的结尾逗号问题。
This leads to cleaner git diffs. Also, transpilers like Babel will remove the additional trailing comma in the transpiled code which means you don't have to worry about the trailing comma problem in legacy browsers.
// 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', ]; // 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) 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 )
-
20.1 Yup. eslint:
semi
jscs:requireSemicolons
// bad (function () { const name = 'Skywalker' return name })() // good (function () { const name = 'Skywalker'; return name; }()); // good, but legacy (guards against the function becoming an argument when two files with IIFEs are concatenated) ;(() => { const name = 'Skywalker'; return name; }());
- 21.1 在语句开始执行强制类型转换。
-
21.2 Strings:
// => this.reviewScore = 9; // bad const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf() // bad const totalScore = this.reviewScore.toString(); // 不能保证返回string类型 // good const totalScore = String(this.reviewScore);
-
21.3 Numbers: 用
Number
做类型转换,parseInt
转换string常需要带上基数。 eslint:radix
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 如果一定要用移位[Bitshifting]运算性能原因, 请在注释中解释为什么和你在做什么
// good /** * parseInt是代码运行慢的原因 * 用Bitshifting将字符串转成数字使代码运行效率大幅增长 */ const val = inputValue >> 0;
-
21.5 注意: 用移位运算要小心. 数字使用64-位表示的,但移位运算常常返回的是32为整形source)。移位运算对大于32位的整数会导致意外行为。Discussion. 最大的32位整数是 2,147,483,647:
2147483647 >> 0 //=> 2147483647 2147483648 >> 0 //=> -2147483648 2147483649 >> 0 //=> -2147483647
-
21.6 布尔:
const age = 0; // bad const hasAge = new Boolean(age); // good const hasAge = Boolean(age); // best const hasAge = !!age;
-
22.1 避免用一个字母命名,让你的命名可描述。 eslint:
id-length
// bad function q() { // ... } // good function query() { // ... }
-
22.2 用小驼峰式命名你的对象、函数、实例。 eslint:
camelcase
jscs:requireCamelCaseOrUpperCaseIdentifiers
// bad const OBJEcttsssss = {}; const this_is_my_object = {}; function c() {} // good const thisIsMyObject = {}; function thisIsMyFunction() {}
-
22.3 用大驼峰式命名类。 eslint:
new-cap
jscs:requireCapitalizedConstructors
// 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 不要用前置或后置下划线。 eslint:
no-underscore-dangle
jscs:disallowDanglingUnderscores
Why? JavaScript 没有私有属性或私有方法的概念。尽管前置下划线通常的概念上意味着“private”,事实上,这些属性是完全公有的,因此这部分也是你的API的内容。这一概念可能会导致开发者误以为更改这个不会导致崩溃或者不需要测试。 如果你想要什么东西变成“private”,那他一定不会再这里出现。
// bad this.__firstName__ = 'Panda'; this.firstName_ = 'Panda'; this._firstName = 'Panda'; // good this.firstName = 'Panda';
-
22.5 不要保存引用
this
, 用箭头函数或函数绑定——Function#bind. jscs:disallowNodeTypes
// 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 export default导出模块A,则这个文件名也叫A.*, import 时候的参数也叫A。 大小写完全一致。
// 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 当你export-default一个函数时,函数名用小驼峰,文件名需要和函数名一致。
function makeStyleGuide() { // ... } export default makeStyleGuide;
-
22.8 当你export一个结构体 用大驼峰 Use PascalCase when you export a constructor / class / singleton / function library / bare object.
const AirbnbStyleGuide = { es6: { } }; export default AirbnbStyleGuide;
-
22.9 Acronyms and initialisms should always be all capitalized, or all lowercased.
Why? Names are for readability, not to appease a computer algorithm.
// 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 = [ // ... ];
- 23.1 Accessor functions 属性不允许使用
-
23.2 不要使用JavaScript的getters/setters,因为他们会产生副作用,并且难以测试、维护和理解。相反的,你可以用 getVal()和setVal('hello')去创造你自己的accessor函数
// bad class Dragon { get age() { // ... } set age(value) { // ... } } // good class Dragon { getAge() { // ... } setAge(value) { // ... } }
-
23.3 如果属性/方法是
boolean
, 用isVal()
或hasVal()
// bad if (!dragon.age()) { return false; } // good if (!dragon.hasAge()) { return false; }
-
23.4 用get()和set()函数是可以的,但是要一起用
class Jedi { constructor(options = {}) { const lightsaber = options.lightsaber || 'blue'; this.set('lightsaber', lightsaber); } set(key, val) { this[key] = val; } get(key) { return this[key]; } }
-
24.1 通过哈希而不是原始值向事件装载数据时(不论是DOM事件还是像Backbone事件的很多属性)。 这使得后续的贡献者(程序员)想这个事件装载更多的数据时不用去找或者更新每个处理器。例如:
// bad $(this).trigger('listingUpdated', listing.id); ... $(this).on('listingUpdated', (e, listingId) => { // do something with listingId });
prefer:
// good $(this).trigger('listingUpdated', { listingId: listing.id }); ... $(this).on('listingUpdated', (e, data) => { // do something with data.listingId });
-
25.1 jQuery对象用
$
变量表示。 jscs:requireDollarBeforejQueryAssignment
// bad const sidebar = $('.sidebar'); // good const $sidebar = $('.sidebar'); // good const $sidebarBtn = $('.sidebar-btn');
-
25.2 暂存jQuery查找
// bad function setSidebar() { $('.sidebar').hide(); // ... $('.sidebar').css({ 'background-color': 'pink' }); } // good function setSidebar() { const $sidebar = $('.sidebar'); $sidebar.hide(); // ... $sidebar.css({ 'background-color': 'pink' }); }
-
25.4 用jQuery对象查询作用域的
find
方法查询// bad $('ul', '.sidebar').hide(); // bad $('.sidebar').find('ul').hide(); // good $('.sidebar ul').hide(); // good $('.sidebar > ul').hide(); // good $sidebar.find('ul').hide();
- 26.1 Refer to Kangax's ES5 compatibility table.
- 27.1 这是收集到的各种ES6特性的链接
- 箭头函数——Arrow Functions
- 类——Classes
- 对象缩写——Object Shorthand
- 对象简写——Object Concise
- 对象计算属性——Object Computed Properties
- 模板字符串——Template Strings
- 解构赋值——Destructuring
- 默认参数——Default Parameters
- Rest
- Array Spreads
- Let and Const
- 迭代器和生成器——Iterators and Generators
- 模块——Modules
-
27.2 Do not use TC39 proposals that have not reached stage 3.
Why? They are not finalized, and they are subject to change or to be withdrawn entirely. We want to use JavaScript, and proposals are not JavaScript yet.
-
28.1 Yup.
function foo() { return true; }
- 28.2 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
at Airbnb.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.
- On Layout & Web Performance
- String vs Array Concat
- Try/Catch Cost In a Loop
- Bang Function
- jQuery Find vs Context, Selector
- innerHTML vs textContent for script text
- Long String Concatenation
- Are Javascript functions like
map()
,reduce()
, andfilter()
optimized for traversing arrays? - Loading...
Learning ES6
- Draft ECMA 2015 (ES6) Spec
- ExploringJS
- ES6 Compatibility Table
- Comprehensive Overview of ES6 Features
Read This
Tools
- Code Style Linters
Other Style Guides
- Google JavaScript Style Guide
- jQuery Core Style Guidelines
- Principles of Writing Consistent, Idiomatic JavaScript
Other Styles
- Naming this in nested functions - Christian Johansen
- Conditional Callbacks - Ross Allen
- Popular JavaScript Coding Conventions on GitHub - JeongHoon Byun
- Multiple var statements in JavaScript, not superfluous - Ben Alman
Further Reading
- Understanding JavaScript Closures - Angus Croll
- Basic JavaScript for the impatient programmer - Dr. Axel Rauschmayer
- You Might Not Need jQuery - Zack Bloom & Adam Schwartz
- ES6 Features - Luke Hoban
- Frontend Guidelines - Benjamin De Cock
Books
- JavaScript: The Good Parts - Douglas Crockford
- JavaScript Patterns - Stoyan Stefanov
- Pro JavaScript Design Patterns - Ross Harmes and Dustin Diaz
- High Performance Web Sites: Essential Knowledge for Front-End Engineers - Steve Souders
- Maintainable JavaScript - Nicholas C. Zakas
- JavaScript Web Applications - Alex MacCaw
- Pro JavaScript Techniques - John Resig
- Smashing Node.js: JavaScript Everywhere - Guillermo Rauch
- Secrets of the JavaScript Ninja - John Resig and Bear Bibeault
- Human JavaScript - Henrik Joreteg
- Superhero.js - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
- JSBooks - Julien Bouquillon
- Third Party JavaScript - Ben Vinegar and Anton Kovalyov
- Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript - David Herman
- Eloquent JavaScript - Marijn Haverbeke
- You Don't Know JS: ES6 & Beyond - Kyle Simpson
Blogs
- JavaScript Weekly
- JavaScript, JavaScript...
- Bocoup Weblog
- Adequately Good
- NCZOnline
- Perfection Kills
- Ben Alman
- Dmitry Baranovskiy
- Dustin Diaz
- nettuts
Podcasts
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
- 4Catalyzer: 4Catalyzer/javascript
- Aan Zee: AanZee/javascript
- Adult Swim: adult-swim/javascript
- Airbnb: airbnb/javascript
- Apartmint: apartmint/javascript
- Ascribe: ascribe/javascript
- Avalara: avalara/javascript
- Avant: avantcredit/javascript
- BashPros: BashPros/javascript
- Billabong: billabong/javascript
- Bisk: bisk/javascript
- Blendle: blendle/javascript
- Bonhomme: bonhommeparis/javascript
- Brainshark: brainshark/javascript
- Chartboost: ChartBoost/javascript-style-guide
- ComparaOnline: comparaonline/javascript
- Compass Learning: compasslearning/javascript-style-guide
- DailyMotion: dailymotion/javascript
- DoSomething: DoSomething/eslint-config
- Digitpaint digitpaint/javascript
- Ecosia: ecosia/javascript
- Evernote: evernote/javascript-style-guide
- Evolution Gaming: evolution-gaming/javascript
- EvozonJs: evozonjs/javascript
- ExactTarget: ExactTarget/javascript
- Expensify Expensify/Style-Guide
- Flexberry: Flexberry/javascript-style-guide
- Gawker Media: gawkermedia/javascript
- General Electric: GeneralElectric/javascript
- GoodData: gooddata/gdc-js-style
- Grooveshark: grooveshark/javascript
- How About We: howaboutwe/javascript
- Huballin: huballin/javascript
- HubSpot: HubSpot/javascript
- Hyper: hyperoslo/javascript-playbook
- InfoJobs: InfoJobs/JavaScript-Style-Guide
- Intent Media: intentmedia/javascript
- Jam3: Jam3/Javascript-Code-Conventions
- JeopardyBot: kesne/jeopardy-bot
- JSSolutions: JSSolutions/javascript
- KickorStick: kickorstick/javascript
- Kinetica Solutions: kinetica/javascript
- Lonely Planet: lonelyplanet/javascript
- M2GEN: M2GEN/javascript
- Mighty Spring: mightyspring/javascript
- MinnPost: MinnPost/javascript
- MitocGroup: MitocGroup/javascript
- ModCloth: modcloth/javascript
- Money Advice Service: moneyadviceservice/javascript
- Muber: muber/javascript
- National Geographic: natgeo/javascript
- National Park Service: nationalparkservice/javascript
- Nimbl3: nimbl3/javascript
- Nulogy: nulogy/javascript
- Orion Health: orionhealth/javascript
- OutBoxSoft: OutBoxSoft/javascript
- Peerby: Peerby/javascript
- Razorfish: razorfish/javascript-style-guide
- reddit: reddit/styleguide/javascript
- React: /facebook/react/blob/master/CONTRIBUTING.md#style-guide
- REI: reidev/js-style-guide
- Ripple: ripple/javascript-style-guide
- SeekingAlpha: seekingalpha/javascript-style-guide
- Shutterfly: shutterfly/javascript
- Springload: springload/javascript
- StratoDem Analytics: stratodem/javascript
- SteelKiwi Development: steelkiwi/javascript
- StudentSphere: studentsphere/javascript
- SysGarage: sysgarage/javascript-style-guide
- Syzygy Warsaw: syzygypl/javascript
- Target: target/javascript
- TheLadders: TheLadders/javascript
- The Nerdery: thenerdery/javascript-standards
- T4R Technology: T4R-Technology/javascript
- VoxFeed: VoxFeed/javascript-style-guide
- WeBox Studio: weboxstudio/javascript
- Weggo: Weggo/javascript
- Zillow: zillow/javascript
- ZocDoc: ZocDoc/javascript
This style guide is also available in other languages:
Brazilian Portuguese: armoucar/javascript-style-guide
Bulgarian: borislavvv/javascript
Catalan: fpmweb/javascript-style-guide
Chinese (Simplified): lin-123/javascript
Chinese (Traditional): jigsawye/javascript
French: nmussy/javascript-style-guide
German: timofurrer/javascript-style-guide
Italian: sinkswim/javascript-style-guide
Japanese: mitsuruog/javascript-style-guide
Korean: tipjs/javascript-style-guide
Polish: mjurczyk/javascript
Russian: uprock/javascript
Spanish: paolocarrasco/javascript-style-guide
Thai: lvarayut/javascript-style-guide
Vietnam: hngiang/javascript-style-guide
- Find us on gitter.
(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.
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.