个人翻译,一些个人见解会用"注:"的形式标出 个人翻译的CSS规范:Airbnb CSS/Sass规范
- 类型
- 引用
- 对象
- 数组
- 解构
- 字符串
- 函数
- 箭头函数
- [类 & 构造函数](#类 & 构造函数)
- 模块
- 迭代器和生成器
- 属性
- 变量
- 变量提升
- [比较运算符 & 相等](#比较运算符 & 相等)
- (代码)块
- 注释
- 空格
- 逗号
- 分号
- 类型转换
- 命名规则
- 存取器
- 事件
- jQuery
- [ECMAScript 5 兼容性](#ECMAScript 5兼容性)
- [ECMAScript 6+ 风格](#ECMAScript 6+ 风格)
- 测试
- 性能
- 资源
- 谁在使用?
- 翻译
- JavaScript编码规范指南
- 和我们聊聊JavaScript
- 贡献者
- 许可
-
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.4 创建动态属性名字的对象时使用计算后的属性名.
Why? 原因:允许你在一个地方定义一个对象的全部属性.
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 使用对象方法简写. 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.6 使用简写属性. eslint:
object-shorthand
jscs:requireEnhancedObjectLiterals
原因:书写描述更简短.
const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { lukeSkywalker: lukeSkywalker, }; // good const obj = { lukeSkywalker, };
-
3.7 将简写属性统一放到对象声明开头.
原因:容易区分使用简写的属性.
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.8 只有加引号的属性是合法的标识符. eslint:
quote-props
jscs:disallowQuotedKeysInObjects
原因:通常我们主观上认为更易读.有利于语法高亮,更容易被许多JS引擎优化.
// bad
const bad = {
'foo': 3,
'bar': 4,
'data-blah': 5,
};
// good
const good = {
foo: 3,
bar: 4,
'data-blah': 5,
};
- 3.9 不要直接使用
Object.prototype
,hasOwnProperty
,propertyIsEnumerable
和isPrototypeOf
等方法.
原因:这些方法可能会被对象自身的同名属性覆盖-考虑
{ hasOwnProperty: false }
或者对象是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 */
const has = require('has');
…
console.log(has.call(object, key));
-
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++) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];
-
4.4 将类数组对象转换成数组使用Array.from.
const foo = document.querySelectorAll('.foo'); const nodes = Array.from(foo);
-
4.5 在数组方法的回调函数中使用return.如果函数体只有一条声明则可以省略return8.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
原因:解构可以避免创建属性的临时引用.
// 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
原因:可以非破坏性地随时增加或者改变属性顺序.
// 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 字符串使用单引号
''
. eslint:quotes
jscs:validateQuoteMarks
// bad const name = "Capt. Janeway"; // bad - template literals should contain interpolation or newlines const name = `Capt. Janeway`; // good const name = 'Capt. Janeway';
-
6.2 一行超过100个字符的字符串不应该使用字符串连接符来跨行书写.
原因:截断的字符串很难维护并且代码不易被搜索查找.
// 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 动态构建字符串时使用模板字符串而不是拼接. eslint:
prefer-template
template-curly-spacing
jscs:requireTemplateStrings
原因:模板字符串有可读性强,语法明确,换行合理和字符串插值的特性.
// 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.5 不要对字符串使用
eval()
,漏洞太多.
-
6.6 不要在字符串中使用不必要的转义字符. eslint:
no-useless-escape
原因:反斜线不利于阅读,应该只在必要的时候出现.
// bad const foo = '\'this\' \i\s \"quoted\"'; // good const foo = '\'this\' is "quoted"'; const foo = `'this' is "quoted"`;
-
7.1 使用函数声明而非函数表达式. eslint:
func-style
jscs:requireFunctionDeclarations
Why? Function declarations are named, so they're easier to identify in call stacks. Also, the whole body of a function declaration is hoisted, whereas only the reference of a function expression is hoisted. This rule makes it possible to always use Arrow Functions in place of function expressions.
// bad const foo = function () { }; // good function foo() { }
-
7.2 用圆括号包裹自执行匿名函数. eslint:
wrap-iife
jscs:requireParenthesesAroundIIFE
Why? An immediately invoked function expression is a single unit - wrapping both it, and its invocation parens, in parens, cleanly expresses this. Note that in a world with modules everywhere, you almost never need an IIFE.
// immediately-invoked function expression (IIFE) (function () { console.log('Welcome to the Internet. Please follow me.'); }());
- 7.3 不要在非函数块(if,while等)中声明函数.要将函数赋给变量.浏览器允许你这么做,但是处理方式不同,这不是好消息. eslint:
no-loop-func
-
7.4 Note: ECMA-262 defines a
block
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 nope(name, options, arguments) { // ...stuff... } // good function yup(name, options, args) { // ...stuff... }
-
7.6 不要使用
arguments
, 使用扩展语法...
. eslint:prefer-rest-params
原因:
...
是你想获得的参数列表,因此,扩展语法的参数是真正的数组,而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 避免参数默认值的副作用.
原因:难以理解.
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 不要使用Function构造函数创建函数. eslint:
no-new-func
原因:此方式创建函数和对字符串使用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
原因:统一为先,不应该在增删名字的同时增删空格.
// bad const f = function(){}; const g = function (){}; const h = function() {}; // good const x = function () {}; const y = function a() {};
-
7.12 不要改变参数. eslint:
no-param-reassign
原因:操作参数中的对象可能在原始调用中造成意想不到的变量副作用.
// 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
原因:参数重新赋值可能会导致无法预期的行为,尤其是当操作
arguments
对象时.也可能导致优化问题,尤其是在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 调用可变参数函数时建议使用扩展运算符
...
. eslint:prefer-spread
原因:显然你无需使用上下文,很难结合
new
和apply
.// 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]);
-
8.1 当你必须使用函数表达式(传递匿名函数)时,使用箭头函数标记. eslint:
prefer-arrow-callback
,arrow-spacing
jscs:requireArrowFunctions
原因:这会创建一个能在其中使用
this
上下文的函数,这是你想要的,语法也更明确.不适用的地方:如果有一个相当复杂的函数,应该把逻辑放到自己的函数声明里.
// 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
原因:语法糖.当进行多个函数的链式操作时可读性好.
// 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 一旦语句跨多行,使用圆括号包裹以便更好阅读.
原因:清晰展示了函数的开始和结束.
// bad [1, 2, 3].map(number => 'As time went by, the string containing the ' + `${number} became much longer. So we needed to break it over multiple ` + 'lines.' ); // good [1, 2, 3].map(number => ( `As time went by, the string containing the ${number} became much ` + 'longer. So we needed to break it over multiple lines.' ));
-
8.4 函数如果只有一个参数并且没用花括号,则省略圆括号. 否则总是使用圆括号包裹参数. eslint:
arrow-parens
jscs:disallowParenthesesAroundArrowParam
原因:看上去不混乱.
// 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’ve broken it ` + 'over multiple lines!' )); // 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
.原因:
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
继承.原因:是实现继承功能而不会破坏
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
原因:重复的类成员声明会默认使用最后声明的-有重复值基本就是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
) . 你可以将其转化为你更喜欢的模块系统.原因:模块是未来,让我们现在开始使用未来的特性.
// 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 不要使用通配符导入.
原因:这会确保你只有一个默认的export.
// bad import * as AirbnbStyleGuide from './AirbnbStyleGuide'; // good import AirbnbStyleGuide from './AirbnbStyleGuide';
-
10.3 不要从import中export.
原因:很显然有一个明确的方法来import和export会保持一致性.
// bad // filename es6.js export { es6 as default } from './airbnbStyleGuide'; // good // filename es6.js import { es6 } from './AirbnbStyleGuide'; export default es6;
-
10.4 只允许在一个地方从一个路径import. eslint:
no-duplicate-imports
原因:从一个路径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 不要export可变的绑定值. eslint:
import/no-mutable-exports
原因:通常来说可变应该被避免,尤其是在export绑定值的时候.通常来说,这个技术只在常量引用被导出的时候使用.
// bad let foo = 3; export { foo } // good const foo = 3; export { foo }
-
10.6 在单一expoort的模块中,建议export default而不是具名export. eslint:
import/prefer-default-export
// bad export function foo() {} // good export default function foo() {}
-
10.7 将所有的
import
放在非import
语句前. eslint:import/imports-first
原因:由于
import
会被提前,将其全部置于顶部会避免意外行为.// bad import foo from 'foo'; foo.init(); import bar from 'bar'; // good import foo from 'foo'; import bar from 'bar'; foo.init();
-
11.1 不要使用迭代器.建议使用JS更高优先级的函数代替
for-in
或for-of
循环. eslint:no-iterator
no-restricted-syntax
原因:这会强化不可变的规则.处理返回值的纯函数要比消除副作用容易.
使用
map()
/every()
/filter()
/find()
/findIndex()
/reduce()
/some()
/ ... 来遍历数组, 用Object.keys()
/Object.values()
/Object.entries()
来制造数组以便能对对象进行迭代.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 现在不要使用生成器.
原因:不能很好地转译为ES5.
-
11.3 如果你非得使用生成器或者无视 建议, 请确保函数签名中的空格正确. eslint:
generator-star-spacing
原因:
function
和*
是同一个概念 -*
不是function
的修饰符,function*是不同于
function的独特的构造函数
.// 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* () { }
-
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
原因:这种方式更易添加变量声明,不用考虑将
;
变成,
.用debugger逐个调试也很方便,而不是一次跳过所有变量.// 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
分别放到一起.原因:当需要给依赖前一个已经赋值的变量的变量赋值时很有用.
// 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 在需要的地方给变量赋值,但位置要合理.
原因:
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 变量不要进行链式赋值.
原因:变量链式赋值会创建隐藏的全局变量.
// 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`
-
14.1
var
声明会被提升到作用域的顶部, 但是赋值不会.const
和let
声明有一个新的概念叫 临时死区 (TDZ). 了解 typeof不再安全很重要.// we know this wouldn't work (assuming there // is no notDefined global variable) function example() { console.log(notDefined); // => throws a ReferenceError } // creating a variable declaration after you // reference the variable will work due to // variable hoisting. Note: the assignment // value of `true` is not hoisted. function example() { console.log(declaredButNotAssigned); // => undefined var declaredButNotAssigned = true; } // the interpreter is hoisting the variable // declaration to the top of the scope, // which means our example could be rewritten as: function example() { let declaredButNotAssigned; console.log(declaredButNotAssigned); // => undefined declaredButNotAssigned = true; } // using const and let function example() { console.log(declaredButNotAssigned); // => throws a ReferenceError console.log(typeof declaredButNotAssigned); // => throws a ReferenceError const declaredButNotAssigned = true; }
-
14.2 匿名函数表达式会提升变量名字而不是函数赋值.
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'); }; } // 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 函数声明会提升函数名和函数体.
function example() { superPower(); // => Flying function superPower() { console.log('Flying'); } }
-
更多信息请参考 JavaScript Scoping & Hoisting by Ben Cherry.
-
15.2 条件声明例如
if
会用ToBoolean
这个抽象方法将表达式转成布尔值并遵循如下规则:- Objects evaluate to true
- Undefined evaluates to false
- Null evaluates to false
- Booleans evaluate to the value of the boolean
- Numbers evaluate to false if +0, -0, or NaN, otherwise true
- Strings evaluate to false if an empty string
''
, otherwise true
if ([0] && []) { // true // an array (even an empty one) is an object, objects will evaluate to true }
-
15.3 使用简写.
// bad if (name !== '') { // ...stuff... } // good if (name) { // ...stuff... } // bad if (collection.length > 0) { // ...stuff... } // good if (collection.length) { // ...stuff... }
- 15.4 更多信息请见 Truth Equality and JavaScript by Angus Croll.
- 15.5 在用
case
和default
语句创建的包含有如下词语(如let
,const
,function
和class
)的代码块中使用花括号 .
原因:这些词语在整个
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
多行代码块,把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) { // ...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 单行注释使用
//
. 在要注释部分的上边一行放置注释. 如果不是块的第一行则在注释前留一个空行.// 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 如果想表明这个问题以后会再次被查看或者给出了这个问题的解决方案,在注释前加上前缀
FIXME
或者TODO
会有利于很快理解问题. 这些不同于一般的注释因为它们是可操作的. 操作是FIXME: -- need to figure this out
或TODO: -- need to implement
.
-
17.4 使用
// FIXME:
来标注问题.class Calculator extends Abacus { constructor() { super(); // FIXME: shouldn't use a global here total = 0; } }
-
17.5 使用
// 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
等). 在函数调用和声明中在参数列表和函数名间不要放置空格. 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 (function (global) { // ...stuff... })(this);
// bad (function (global) { // ...stuff... })(this);↵ ↵
// good (function (global) { // ...stuff... })(this);↵
-
18.6 进行长的函数链式调用时使用缩进(超过两个方法的链式调用).为了强调该行是方法调用而不是新的语句声明要用.开头. 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个字符(包括空格). 注意: above,不包括整体不应爱被分割的长字符串. eslint:
max-len
jscs:maximumLineLength
原因:确保可读性和可维护性.
// 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
原因:会让git diff更干净. 你不必担心老式浏览器的问题 结尾逗号问题因为Babel转译器会在转译后的代码中移除额外的逗号.
// 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', ];
-
20.1 需要使用分号 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(); // isn't guaranteed to return a string // good const totalScore = String(this.reviewScore);
-
21.3 数字: 使用
Number
进行转换,使用带基数的parseInt
对字符串进行转换. 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 不管什么原因你使用了
parseInt
,到达了性能瓶颈,你需要使用位运算性能原因, 请注释说明这么做的原因.// good /** * parseInt was the reason my code was slow. * Bitshifting the String to coerce it to a * Number made it a lot faster. */ const val = inputValue >> 0;
-
21.5 注意: 使用位运算请小心. 数字使用 64位值表示, 但是位运算只返回32位整数 (代码). 小于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() { // ...stuff... } // good function query() { // ..stuff.. }
-
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
原因:Javascript对于属性和方法并没有隐私的概念.尽管下划线开头通常意味着'private', 事实上这些属性是完全公开的,是公开API的一部分. 这种风格可能导致开发者错误地认为这不重要或者测试也不必要. 也就是说: 如果你想让其 “private”, 必须使其不可见.
// bad this.__firstName__ = 'Panda'; this.firstName_ = 'Panda'; this._firstName = 'Panda'; // good this.firstName = 'Panda';
-
22.5 不要保存指向
this
的引用. 使用箭头函数或 函数的#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 基本的文件名应该和默认导出的名字刚好匹配.
// 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 Use camelCase when you export-default a function当默认导出一个函数时使用驼峰风格. 文件名要和函数名相同.
function makeStyleGuide() { } export default makeStyleGuide;
-
22.8 当导出 构造函数 / 类 / 单例 / 函数库 / 对象时使用帕斯卡风格.
const AirbnbStyleGuide = { es6: { } }; export default AirbnbStyleGuide;
- 23.1 属性的存取器不是必需的.
-
23.2 不要使用JavaScript getters/setters 因为可能引起不可预期的副作用很难测试维护和理解. 相反,如果要使用存取器函数,使用 getVal() 和 setVal('hello').
// 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 });
建议:
// 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(); // ...stuff... $('.sidebar').css({ 'background-color': 'pink' }); } // good function setSidebar() { const $sidebar = $('.sidebar'); $sidebar.hide(); // ...stuff... $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 参考 Kangax's ES5 compatibility table.
- 27.1 这是不同ES6特性的链接集合.
-
28.1 建议
function foo() { return true; }
- 28.2 不要这么做,很严重:
- 不论你用哪一个测试框架,都应该写测试用例!
- 尽力写一些简洁的函数, 使改动数据的部分最小化.
- 小心使用 stubs 和 mocks - 它们会使测试变得脆弱.
- 我们在Airbnb中主要使用
mocha
.tape
有时也用于小的独立模块. - 100%的测试覆盖率是需要努力达成的目标,即使这是不切实际的.
- 无论何时修复bug, 写回归测试. 没有回归测试的bug修复几乎会在将在再次出现.
- 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...
学习 ES6
- Draft ECMA 2015 (ES6) Spec
- ExploringJS
- ES6 Compatibility Table
- Comprehensive Overview of ES6 Features
阅读
工具
- Code Style Linters
其他编码规范指南
- Google JavaScript Style Guide
- jQuery Core Style Guidelines
- Principles of Writing Consistent, Idiomatic JavaScript
其他风格
- 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
更深的阅读
- 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
书籍
- 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
博客
- DailyJS
- JavaScript Weekly
- JavaScript, JavaScript...
- Bocoup Weblog
- Adequately Good
- NCZOnline
- Perfection Kills
- Ben Alman
- Dmitry Baranovskiy
- Dustin Diaz
- nettuts
播客
这是一份使用这份编码规范的组织列表.给我们提PR我们会把你加到这份列表里.
- 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
- Billabong: billabong/javascript
- Bisk: bisk/javascript
- Blendle: blendle/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
- 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
- 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
其他语言的版本:
- Brazilian Portuguese: armoucar/javascript-style-guide
- Bulgarian: borislavvv/javascript
- Catalan: fpmweb/javascript-style-guide
- Chinese (Simplified): sivan/javascript-style-guide
- 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: giangpii/javascript-style-guide
- Find us on gitter.
(The MIT License)
Copyright (c) 2014-2016 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.
我们鼓励你fork这份指南并改变规则来适应你团队的风格.你还可以列出一些修改补充.这可以让你不用处理合并冲突就可以定期升级编码规范指南