// bad
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i < len; i++) {
itemsCopy[i] = items[i];
}
// good
const itemsCopy = [...items];
// 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.';
// bad
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// bad
function sayHi(name) {
return ['How are you, ', name, '?'].join();
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
// 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.'
));
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
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;
function example() {
console.log(anonymous); // => undefined
anonymous(); // => TypeError anonymous is not a function
var anonymous = function () {
console.log('anonymous function expression');
};
}
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');
}
}
// bad
if (name !== '') {
// ...stuff...
}
// good
if (name) {
// ...stuff...
}
// bad
if (collection.length > 0) {
// ...stuff...
}
// good
if (collection.length) {
// ...stuff...
}
// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function () { return false; }
// good
function () {
return false;
}
16.2 如果在 if 和 else 的语句中使用多行快,则将 else 与 if 块的反括号放在同一行。
// 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;
}
// bad
if(isJedi) {
fight ();
}
// good
if (isJedi) {
fight();
}
// bad
function fight () {
console.log ('Swooosh!');
}
// good
function fight() {
console.log('Swooosh!');
}
// 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);
}
// bad
function bar( foo ) {
return foo;
}
// good
function bar(foo) {
return foo;
}
// bad
if ( foo ) {
console.log(foo);
}
// good
if (foo) {
console.log(foo);
}
// bad
(function () {
const name = 'Skywalker'
return name
})()
// good
(() => {
const name = 'Skywalker';
return name;
})();
// good (guards against the function becoming an argument when two files with IIFEs are concatenated)
;(() => {
const name = 'Skywalker';
return name;
})();
// => this.reviewScore = 9;
// bad
const totalScore = this.reviewScore + '';
// good
const totalScore = String(this.reviewScore);
21.3 数字: 使用 Number 进行类型转换。在使用 parseInt 转换字符串时要始终带着基数。
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);
// 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',
});
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
// good
this._firstName = 'Panda';
22.5 请勿保存 this 的引用。采用箭头函数或Function#bind(译者注:Function.prototype.bind())。
// 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);
};
}
// file contents
class CheckBox {
// ...
}
export default CheckBox;
// in some other file
// bad
import CheckBox from './checkBox';
// bad
import CheckBox from './check_box';
// good
import CheckBox from './CheckBox';
// bad
$(this).trigger('listingUpdated', listing.id);
...
$(this).on('listingUpdated', function (e, listingId) {
// do something with listingId
});
而是:
// good
$(this).trigger('listingUpdated', { listingId: listing.id });
...
$(this).on('listingUpdated', function (e, data) {
// do something with data.listingId
});
// bad
$('ul', '.sidebar').hide();
// bad
$('.sidebar').find('ul').hide();
// good
$('.sidebar ul').hide();
// good
$('.sidebar > ul').hide();
// good
$sidebar.find('ul').hide();
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.
Airbnb JavaScript Style Guide() {
JavaScript中更合理的使用方法
![Gitter](https://badges.gitter.im/Join Chat.svg)
其他风格指南
目录
类型
1.1 基本类型: 按值访问,操作的是值.
string
number
boolean
null
undefined
1.2 引用类型: 按引用访问,操作的是值的指针.
object
array
function
⬆ 返回顶部
引用
2.1 使用
const
来声明所有引用; 避免使用var
.eslint 规则:
prefer-const
,no-const-assign
.2.2 如果一定要为变量重新赋值,则使用
let
代替var
。eslint 规则:
no-var
.2.3 记住
let
和const
都是块级作用域.⬆ 返回顶部
对象
3.1 使用字面量方式创建对象。
eslint 规则:
no-new-object
.3.2 如果你的代码将在浏览器环境中运行, 请不要使用保留字作为键,这样会在IE8下报错(查看更多). 但可以在ES6的模块中或服务器端正常使用。
3.3 使用可读性强的同义词代替保留字.
3.4 当需要使用动态属性名来创建对象时,请使用计算后的属性名。
3.5 使用方法简写.
eslint 规则:
object-shorthand
.3.6 使用属性简写.
eslint 规则:
object-shorthand
.3.7 在对象声明的开头定义需要简写的属性。
⬆ 回到顶部
数组
4.1 使用字面量方式创建数组。
eslint 规则:
no-array-constructor
.4.2 使用 Array#push,而不是直接为数组添加元素。
4.3 使用数组扩展运算符
...
来复制数组。4.4 使用 Array#from 将一个类数组对象转换成数组。
⬆ 返回顶部
解构
5.1 当访问和使用对象的多个属性时,使用对象解构赋值。
5.2 使用数组解构赋值。
5.3 使用对象解构来实现多值返回,而不使用数组解构。
⬆ 返回顶部
字符串
6.1 字符串变量使用单引号
''
。eslint 规则:
quotes
.6.3 注意: 如果过度使用,用连接符连接字符串可能会影响性能jsPerf & Discussion.
6.4 当使用编程的方式来构建字符串时,应采用模板字符串,而不是字符串拼接。
eslint 规则:
prefer-template
.eval()
方法,它会带来太多的漏洞。⬆ 返回顶部
函数
7.1 使用函数声明,而不是函数表达式。
7.2 函数表达式:
7.4 注意: ECMA-262将
block
定义为语句列表。而函数声明并不是一条语句。阅读 ECMA-262 关于此问题的说明.7.5 永远不要将参数命名为
arguments
。这将覆盖原函数作用域的arguments
对象。7.6 永远不要使用
arguments
,可以选择使用rest语法...
代替。7.7 使用默认参数语法,而不是改变函数参数。
7.8 避免默认参数的副作用。
7.9 将默认参数放在最后。
7.10 永远不要使用函数构造器来创建一个新函数。
7.11 在函数签名中添加空格.
⬆ 返回顶部
箭头函数
8.1 如果必须要使用函数表达式(当传递一个匿名函数时),请使用箭头函数符号。
eslint 规则:
prefer-arrow-callback
,arrow-spacing
.8.2 如果函数体仅包含一个表达式,可去掉大括号,采用隐式返回。除此之外,请使用
return
语句。eslint 规则:
arrow-parens
,arrow-body-style
.8.3 当一个返回的表达式跨越多行时,为了更好的可读性将他们用括号括起来。
8.4 如果函数只有一个参数,可省略括号。
eslint 规则:
arrow-parens
.⬆ 返回顶部
构造器
9.1 始终使用
class
,避免直接操作prototype
。9.2 使用
extends
语法实现继承。9.3 各方法可返回
this
来实现方法的链式调用。9.4 可以自己写一个toString()方法,只需要保证他能正确运行并没有副作用即可。
⬆ 返回顶部
模块
10.1 始终使用模块(
import
/export
),而不是非标准的模块系统。这样你就能随时迁移到您更青睐的模块系统。10.2 不要使用通配符引用。
10.3 不要直接在引用的位置输出。
⬆ 返回顶部
迭代器与生成器
11.1 不要使用迭代器。尽量使用Javascript的高阶函数,比如
map()
和reduce()
,来替代for-of
之类的循环。eslint 规则:
no-iterator
.11.2 现在不要使用生成器。
⬆ 返回顶部
属性
12.1 使用点标记访问属性。
eslint 规则:
dot-notation
.12.2 当属性为变量时,采用中括号
[]
。⬆ 返回顶部
变量
13.1 始终使用
const
来声明变量,否则会导致全局变量。地球超人告诫我们要避免污染全局命名空间。13.2 每个变量都使用一个
const
声明。eslint 规则:
one-var
.13.3 将所有的
const
和let
分组。13.4 在需要的地方为变量赋值,但应把他们放在合理的地方。
⬆ 返回顶部
提升
14.1
var
变量的声明将会被提升到作用域的顶部,但赋值却不会。通过const
和let
声明的变量被赋予了新的概念叫做时空盲区(TDZ)。重要的是要知道为什么typeof不再安全。14.2 匿名函数表达式的变量名会提升,但函数的赋值不会。
14.3 被命名的函数表达式的变量名会被提升,而函数名和函数体则不会。
14.4 函数声明会提升函数名和函数体。
⬆ 返回顶部
比较操作
===
和!==
来代替==
和!=
.15.2 像
if
一样的条件语句会强制使用ToBoolean
抽象方法来计算他的表达式,这种强制转换始终遵循以下这些简单的规则:eslint 规则:
eqeqeq
.字符串:如果是空字符串
''
,则转化成 false, 否则 true15.3 使用简写。
⬆ 返回顶部
块
16.1 将所有的多行块用大括号括起来。
16.2 如果在
if
和else
的语句中使用多行快,则将else
与if
块的反括号放在同一行。eslint 规则:
brace-style
.⬆ 返回顶部
注释
17.1 多行注释请使用
/** ... */
。函数的注释应包含函数描述,所有参数的指定类型和值,以及返回值。17.2 单行注释请使用
//
。将单行注释放到要注释的内容的上一行,且独占一行。在注释行的前面加一个空行,除非该注释是块的第一行。FIXME
或TODO
,能帮助其他开发者马上理解你是在指出一个需要解决的问题,还是在提出一个问题的解决方案。这种与正常的注释不同,因为他们是可操作的。该操作包括FIXME -- 需要搞清楚这个问题
和TODO -- 需要实现
。17.4 Use
// FIXME:
to annotate problems. 使用// FIXME:
注释问题。17.5 使用
// TODO:
注释问题的解决方案。⬆ 返回顶部
空白
18.1 将tab设置为2空格。
eslint 规则:
indent
.18.2 在左大括号的前面加一个空格。
eslint 规则:
space-before-blocks
.18.3 在控制语句中(
if
、while
等)的左小括号的前面加一个空格。但在函数调用或声明中的参数列表前不应加空格。eslint 规则:
space-after-keywords
,space-before-keywords
.18.4 操作符两侧都要加空格.
eslint 规则:
space-infix-ops
.18.5 在文件的最后加一个空行。
18.6 当使用较长的方法链式调用时,应采用缩进。在前方加点,这会突出该行是一个方法调用,而不是一个新的语句。
18.7 在块的后面和下一个语句之前加一个空行。
18.8 不要用空行包装你的块内容。
eslint 规则:
padded-blocks
.18.9 不要在小括号内添加空格。
eslint 规则:
space-in-parens
.18.10 不要在中括号内添加空格。
eslint 规则:
array-bracket-spacing
.18.11 在单行大括号内添加空格。
eslint rules:
object-curly-spacing
.⬆ 返回顶部
逗号
19.1 逗号开头: 不要.
eslint 规则:
comma-style
.19.2 添加尾随逗号: 是.
eslint 规则:
no-comma-dangle
.⬆ 返回顶部
分号
20.1 语句结尾要有分号.
eslint 规则:
semi
.更多.
⬆ 返回顶部
类型转换
21.2 字符串:
21.3 数字: 使用
Number
进行类型转换。在使用parseInt
转换字符串时要始终带着基数。21.4 如果由于某种原因,你要做一些不可控(wild)事情,
parseInt
方法会是你的瓶颈。由于性能原因,此时就需要使用比特位移(Bitshift),然后再注释一下为什么这么做以及怎么做的。21.5 注意: 在使用比特位移时要格外小心。 数字采用64位值展示,但比特位移操作只能返回32位整数(参考)。比特位移在操作超过32位的整数时,会产生意外行为。讨论。最大的32位整数是2,147,483,647:
21.6 布尔值:
⬆ 返回顶部
命名约定
22.1 避免用单字母作为名称。要让命名有意义。
22.2 在命名对象、函数和实例时,采用驼峰方式。
eslint 规则:
camelcase
.22.3 在命名构造器或类时,采用帕斯卡命名法(译者注:所有单词首字母大写且直接相连)。
22.4 在命名私有属性时,采用前置下划线
_
方式。eslint 规则:
no-underscore-dangle
.22.5 请勿保存
this
的引用。采用箭头函数或Function#bind(译者注:Function.prototype.bind())。22.6 如果你的文件只包含一个类,则文件名应该与类名完全一致。
22.7 文件导出的默认函数应采用驼峰方式命名,同时文件名应该与函数名一致。
22.8 当文件导出的是一个单例、或函数库、或仅是一个对象时,采用帕斯卡拼写法。
⬆ 返回顶部
访问器
23.2 如果要编写访问器函数,采用
getVal()
和setVal('hello')
的写法。23.3 若访问的属性是
boolean
类型,则采用isVal()
或hasVal()
的写法。23.4 也可以创建
get()
和set()
函数,但要保持一致。⬆ 返回顶部
事件
24.1 当触发事件携带参数时(无论是DOM事件,还是带有其他更多属性的像Backbone的事件),请传递一个hash对象,而不是单个值。这使得的在随后想通过事件传递更多数据时,无需找到并更新所有事件的处理函数。举例,不是:
而是:
⬆ 返回顶部
jQuery
25.1 在jQuery对象的变量前加一个
$
。25.2 缓存jQuery的查找值.
$('.sidebar ul')
或 父子级形式$('.sidebar > ul')
。jsPerf25.4 对于有范围的jQuery对象查询采用
find
方法。⬆ 返回顶部
ES5兼容性
⬆ 返回顶部
ES6风格
⬆ 返回顶部
测试
28.1 对.
mocha
。对于小的、单独的模块,我们有时也会使用tape
。⬆ 返回顶部
性能
⬆ 返回顶部
资源
ES6学习
请阅读
工具
其他风格指南
其他风格
延伸阅读
书籍
博客
播客
⬆ 返回顶部
使用者
这是正在使用此风格指南的组织列表。若您也使用,给我们发个提交请求,我们会将您加入到列表中。
⬆ 返回顶部
翻译
此篇风格指南还有其他语言版本:
JavaScript风格指南手册
一起讨论JavaScript
贡献者
许可证
(The MIT License)
Copyright (c) 2014 Airbnb
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
⬆ back to top
修订
我们鼓励您拷贝该指南,并改变规则来适应你的团队风格。在下面,你可以列出一些针对该风格指南的修正。这使您可以定期更新你的风格指南,而不必处理合并冲突。
};