- JavaScript 文件使用无 BOM 的 UTF-8 编码。
为什么? UTF-8 编码具有更广泛的适应性。BOM 在使用程序或工具处理文件时可能造成不必要的干扰,比如Mac系统中的换行符问题。
-
使用 4 个空格。
// bad function fn() { ∙∙var name; } // good function fn() { ∙∙∙∙var name; }
-
每个独立语句结束后必须换行。
// bad user.setCode(1); user.setName('admin'); user.setPwd('123456'); // good user.setCode(1); user.setName('admin'); user.setPwd('123456');
-
if
、else
、switch
、case
、for
、while
和:
后1个空格。// bad if(a > b) { } // good if (a > b) { } // bad for(var i = 0; i < 5; i++) { // ... } // good for (var i = 0; i < 5; i++) { // ... }
-
赋值语句两边各 1 个空格
// bad name='John'; // good name = 'John';
-
两元运算符(
==
,>
,<
等)两边各 1 个空格。// bad if (a==b) { } // good if (a == b) { }
-
函数参数之间 1 个空格。
// bad function ajax(url,param,success) { // ... } // good function ajax(url, param, success) { // ... }
-
左大括号前 1 个空格。
// bad function ajax(url, param, success){ // ... } if (a > b){ } // good function ajax(url, param, success) { // ... } if (a > b) { }
-
一元运算符(
++
,--
)前后不加空格。// bad ++ sum; total --; // good ++sum; total--;
-
语句始终使用分号结尾,
for
、function
、if
、switch
、try
、while
除外,不要依赖于引擎隐式插入。// bad function fn() { // ... }; // good function fn() { // ... } // bad for (var i = 0; i < 5; i++) { // ... }; // good for (var i = 0; i < 5; i++) { // ... }
-
不要将逗号放前面。
// bad var hero = { firstName: 'Bob' , lastName: 'Parr' , heroName: 'Mr. Incredible' , superPower: 'strength' }; // good var hero = { firstName: 'Bob', lastName: 'Parr', heroName: 'Mr. Incredible', superPower: 'strength' };
-
起首的大括号跟在关键字的后面,且大括号前留有一个空格。
// bad if (a > b) { // ... } // good if (a > b) { // ... } // 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' });
-
数组成员以逗号分隔,逗号后加 1 个空格。
// bad var arr = [1,2,3,4]; // good var arr = [1, 2, 3, 4];
-
小括号作为函数调用时函数名与左小括号之间没有空格。
// bad func (); // good func();
-
小括号作为强制运算符时左括号前加 1 个空格。
// bad return(x + y); // good return (x + y);
-
行的长度不应超过80个字符,如果超过应当在运算符(逗号,加号等)后换行。下一行增加两级缩进(8个空格)。
// bad doSomething(argument1, argument2, argument3, argument4, argument5); doSomething(argument1, argument2, argument3, argument4, argument5); // good doSomething(argument1, argument2, argument3, argument4, argument5);
-
在单行注释符后留一个空格。
// bad //this is comment // good // this is comment
-
在多行注释的结束符前留一个空格,使星号对齐。
// bad /* this is comment */ // good /* this is comment */
-
不要把注释写在多行注释的开始符、结束符所在行。
// bad /* start end */ /* here is line 1 here is line 2 */ // good /* start end */ /* here is line 1 here is line 2 */
-
2.1 使用对象直接量创建对象。
// bad var item = new Object(); // good var item = {};
-
2.2 不要使用 保留字 当 key,IE8 里有 bug, 查看更多。
// bad var superman = { default: { clark: 'kent' }, private: true }; // good var superman = { defaults: { clark: 'kent' }, hidden: true };
-
2.3 使用可读性更好的同义词来替代保留字。
// bad var superman = { class: 'alien' } // good var superman = { type: 'alien' }
-
3.1 使用数组直接量定义数组。
// bad var items = new Array(); // good var items = [];
-
3.2 如果你不知道数组的长度,使用 push。
var someStack = []; // bad someStack[someStack.length] = 'abababa'; // good someStack.push('abababa');
-
3.3 复制数组使用 slice。
// bad var len = items.length; var itemsCopy = []; for (var i = 0; i < len; i++) { itemsCopy[i] = items[i] } // good var itemsCopy = items.slice();
-
var foo = document.querySelectorAll('.foo'); var nodes = Array.prototype.slice.call(foo);
-
4.1 使用单引号定义字符串。
// bad var name = "Capt. Janeway"; // good var name = 'Capt. Janeway';
-
4.2 超过80个字符的字符串采用加号
+
, 多行显示。// bad var errorMessage = 'This is a super error that was thrown because of Batman. When you stop how Batman had anything to do with this, you would get nowhere fast.'; // bad var errorMessage = 'This is a super error that was thrown because \ of Batman. When you stop how Batman had anything to do \ with this, you would get nowhere fast.'; // good var errorMessage = 'This is a super error that was thrown because ' + 'of Batman. When you stop how Batman had anything to do ' + 'with this, you would get nowhere fast.';
-
4.3 HTML属性使用双引号,即单引号在外层,双引号在内层。
// bad var html = "<a href='http://www.jd.com'>京东</a>"; // good var html = '<a href="http://www.jd.com">京东</a>';
-
4.4 编程时使用
join
而不是字符串连接来构建字符串。
var items;
var messages;
var i, length;
messages = [{
state: 'success',
message: 'This one worked.'
},{
state: 'success',
message: 'This one worked as well.'
},{
state: 'error',
message: 'This one did not work.'
}];
length = messages.length;
// bad
function inbox(messages) {
items = '<ul>';
for (i = 0; i < length; i++) {
items += '<li>' + messages[i].message + '</li>';
}
return items + '</ul>';
}
// good
function inbox(messages) {
items = [];
for (i = 0; i < length; i++) {
items[i] = messages[i].message;
}
return '<ul><li>' + items.join('</li><li>') + '</li></ul>';
}
```
**[返回列表](#table-of-contents)**
## <a name="properties">属性</a>
- [6.1](#6.1) <a name='6.1'></a> 使用点号 `.` 访问对象属性。
```javascript
var luke = {
jedi: true,
age: 28,
};
// bad
var isJedi = luke['jedi'];
// good
var isJedi = luke.jedi;
```
- [6.2](#6.2) <a name='6.2'></a> 当使用变量访问属性时使用中括号 `[]`。
```javascript
var luke = {
jedi: true,
age: 28,
};
function getProp(prop) {
return luke[prop];
}
var isJedi = getProp('jedi');
```
**[返回列表](#table-of-contents)**
## <a name="variables">变量</a>
- [7.1](#7.1) <a name='7.1'></a> 使用 `var` 来声明变量,否则会产生全局变量,避免污染全局命名空间。
```javascript
// bad
superPower = new SuperPower();
// good
var superPower = new SuperPower();
```
- [7.2](#7.2) 命名采用驼峰式,第一个单词小写,之后的单词首字母大写。
```javascript
// bad
var nickname = 'John';
var nick_name = 'John';
// good
var nickName = 'John';
```
- [7.3](#7.3) 常量名全部用大写字母。
```javascript
// bad
var pi = 3.1415926;
// good
var PI = 3.1415926;
```
- [7.4](#7.4) 避免单个字符名,变量名应具有描述意义(计数器除外)。
```javascript
// bad
function q() {
// ...stuff...
}
// good
function query() {
// ..stuff..
}
```
- 类(构造器)名首字母大写,用名词。
```javascript
// bad
function person(name, age) {
this.name = name;
this.age = age;
}
// good
function Person(name, age) {
this.name = name;
this.age = age;
}
```
- [7.2](#7.2) <a name='7.2'></a> 使用多个 `var` 以及新行声明多个变量。
```javascript
// bad
var items = getItems(),
goSportsTeam = true,
dragonball = 'z';
// good
var items = getItems();
var goSportsTeam = true;
var dragonball = 'z';
```
- [7.3](#7.3) <a name='7.3'></a> 就近声明,用时声明,更自然的在视角范围内。
```javascript
// bad
var i, len;
var goSportsTeam = true;
var dragonball = 'z';
// ...
for (i = 0; i < len; i++) {
// ...
}
// good
var goSportsTeam = true;
var dragonball = 'z';
// ...
for (var i = 0, len = arr.length; i < len; i++) {
// ...
}
```
- [7.4](#7.4) <a name='7.4'></a> 最后声明未赋值的变量,当你想引用之前已赋值变量的时候很有用。
```javascript
// bad
var width;
var height;
var $div = $('#nav');
// good
var $div = $('#nav');
var width = $div.width();
var height = $div.height();
```
- [7.5](#7.5) <a name='7.5'></a> 变量应先声明后使用,避免 `变量提升` 现象产生。
```javascript
// bad
function fn() {
doStaff(width, height);
var width = $div.width() || 0;
var height = $div.height() || 0;
}
// good
function fn() {
var width = $div.width() || 0;
var height = $div.height() || 0;
doStaff(width, height);
}
```
- [7.6](#7.6) <a name='7.6'></a> 分组声明:变量多且有明显相关性时。
```javascript
// bad
var x, y, z, width, height;
// good
var x, y, z;
var width, height;
```
- 前缀参考
<table>
<thead>
<tr><td>前缀</td><td>类型</td><td>示例</td></tr>
</thead>
<tbody>
<tr><td>is, can has</td><td>Boolean</td><td>isPass</td></tr>
<tr><td>get</td><td>Getter</td><td>getName</td></tr>
<tr><td>set</td><td>Setter</td><td>setName</td></tr>
<tr><td>i, j, k</td><td>iterator</td><td></td></tr>
<tr><td>el</td><td>HTMLElement</td><td>elNav</td></tr>
<tr><td>$</td><td>jQuery Object</td><td>$nav</td></tr>
</tbody>
</table>
**[返回列表](#table-of-contents)**
## <a name="conditionals">条件表达式和等号</a>
- [8.1](#8.1) <a name='8.1'></a> 严格比较使用 `===` 和 `!==` ,宽松比较使用 `==` 和 `!=`。多数时候请使用`严格比较`。
- [8.2](#8.2) <a name='8.2'></a> 条件表达式的转换内部执行ES规范里抽象方法的 `ToBoolean`, 遵循以下规则:
+ **对象** 转换为 **true**
+ **Undefined** 转化为 **false**
+ **Null** 转换为 **false**
+ **Boolean** 转换为 **布尔自身的值**
+ **Number** 如果是 **+0, -0, or NaN** 转换为 **false**,其它转换成 **true**
+ **String** 如果是 空字符串 `''` 转换成 **false** , 其它转化成 **true**
```javascript
if ([0]) {
// true
// An array is an object, objects evaluate to true
}
```
- [8.3](#8.3) <a name='8.3'></a> 使用快捷方式。
```javascript
// bad
if (name !== '') {
// ...stuff...
}
// good
if (name) {
// ...stuff...
}
// bad
if (collection.length > 0) {
// ...stuff...
}
// good
if (collection.length) {
// ...stuff...
}
// bad
if ($nav.length > 0) {
// ...stuff...
}
// good
if ($nav.length) {
// ...stuff...
}
```
**[返回列表](#table-of-contents)**
## <a name="blocks">语句</a>
- [9.1](#9.1) <a name='9.1'></a> 所有多行语句的块使用大括号。
```javascript
// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function() { return false; }
// good
function() {
return false;
}
```
- [9.2](#9.2) <a name='9.2'></a> `if` 和 `else` 块, 把 `else` 和第一个块的结束行放在一行。
```javascript
// bad
if (test) {
thing1();
thing2();
}
else {
thing3();
}
// good
if (test) {
thing1();
thing2();
} else {
thing3();
}
```
**[返回列表](#table-of-contents)**
## <a name="functions">函数</a>
- 函数的长度控制在 50 行以内。
> 为什么?将过多的逻辑单元混在一个大函数中,难以维护。一个清晰易懂的函数应该完成单一的逻辑单元。复杂的操作应进一步分解,通过函数的调用来体现流程。
> 不可分割的特定算法逻辑允许例外。
- 函数的参数控制在 5 个以内,过多参数会导致维护难度增大。
> 为什么? 有些函数的参数并非作为算法的输入,而是对算法的某些分支条件判断之用,此类参数建议通过一个JS对象 options 传递。
> 某些情况下,如使用 AMD/CMD Loader 的 require 加载多个模块时,其 callback 可能会存在较多参数,因此对函数参数的个数不做强制限制。
- [5.1](#5.1) <a name='5.1'></a> 使用函数声明替代函数表达式。
```javascript
// bad
var foo = function () {
};
// good
function foo() {
}
```
- [5.2](#5.2) <a name='5.2'></a> 函数表达式。
```javascript
// immediately-invoked function expression (IIFE)
(function() {
console.log('Welcome to the Internet. Please follow me.');
})();
```
- [5.3](#5.3) <a name='5.3'></a> 不要将一个函数定义非函数块内,如 `if` 、 `while` 语句等。虽然浏览器允许这么干,但在各个浏览器中 <a href="http://w3help.org/zh-cn/causes/SJ9002" target="_blank">表现不一致</a>。
```javascript
if (boo) {
function bar() {alert(1);}
} else {
function bar() {alert(2);}
}
```
- [5.4](#5.4) <a name='5.4'></a> 参数不要命名为 `arguments`,该名在函数内自动创建。
```javascript
// bad
function nope(name, options, arguments) {
// ...stuff...
}
// good
function yup(name, options, args) {
// ...stuff...
}
```
**[返回列表](#table-of-contents)**
## <a name="type-casting--coercion">类型转换</a>
- [10.1](#10.1) <a name='10.1'></a> 字符串。
```javascript
// => this.reviewScore = 9;
// bad
var totalScore = this.reviewScore + '';
// good
var totalScore = String(this.reviewScore);
```
- [10.2](#10.2) <a name='10.2'></a> 数字使用 `parseInt` 且总是带上类型转换的基数。
```javascript
var inputValue = '4';
// bad
var val = new Number(inputValue);
// bad
var val = +inputValue;
// bad
var val = inputValue >> 0;
// bad
var val = parseInt(inputValue);
// good
var val = Number(inputValue);
// good
var val = parseInt(inputValue, 10);
```
- [10.3](#10.3) <a name='10.3'></a> 出于 [性能考虑](http://jsperf.com/coercion-vs-casting/3), `parseInt` 不能满足要求时,使用位操作符 `>>` 转换,请注释说明。
```javascript
// good
/**
* 此处对性能要求较高,不采用 parseInt 转换,使用 >> 会更快.
*/
var val = inputValue >> 0;
```
- [10.4](#10.4) <a name='10.4'></a> **注意:** 当使用位移操作要小心,数字以 64 位存储,但 `>>` 最大以 32位运算。因此能转换的最大数字是 2,147,483,647。 超过该范畴的会出现错误:
```javascript
2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647
```
- [10.6](#10.5) <a name='10.5'></a> 布尔。
```javascript
var age = 0;
// bad
var hasAge = new Boolean(age);
// good
var hasAge = Boolean(age);
// good
var hasAge = !!age;
```
**[返回列表](#table-of-contents)**