Author: Nicholas C. Zakas
第 2 章, 注释
单行注释
单行注释的原则:
- 如果注释独占一行, 它应该用于解释接下来一行的代码, 并在之前留一个空行, 缩进与下一行一致
- 如果注释放在行尾, 它应该与代码保持一个缩进以上的距离, 如果注释使单行代码超长, 应该让其独占一行
- 如果注释超过一行, 应该改为多行注释
多行注释
一个良好实践:
if (condition) {
/*
* 多行注释前留一个空行
* 在多行注释起始行后另起一行开始注释内容
* 在多行注释的每一行前加一个星号, 在星号后再加一个空格
* 同样另起一行结束注释
*/
doSomething();
}
注释的使用
注释不是越多越好, 应该审慎地使用注释. 在以下几种情况下使用注释:
1. 难以理解的代码
2. 可以被误认为错误的代码
有的时候代码逻辑有可能被阅读者误解, 这种情况建议添加注释说明.
3. 浏览器特性 hack
一些针对老旧版本的浏览器 hack 的代码常常需要注释才能让人理解作用.
文档注释
文档注释不是 JavaScript 代码的组成部分, 但它们是一种普遍的实践, 参见 Javadoc - Wikipedia. 如果使用了文档注释, 就应当为: 所有的方法, 所有的构造函数, 及所有包含文档化方法的对象添加文档注释, 并在整个项目中保持格式和用法统一.
第 3 章, 语句和表达式
尽管单行语句的花括号可以被省略, 但省略花括号会造成一些困惑, 所以, 应该把任何块语句包裹在花括号中.
花括号对齐
虽然没有强制规定, 但是大多数指南推荐使用行末花括号:
// 不推荐
if (condition)
{
doSomething();
}
// 推荐
if (condition) {
doSomething();
}
块语句间隔
块语句间隔应该在以下三种方案中形成统一:
if(condition){
doSomething();
}
if (condition) {
doSomething();
}
if ( condition ) {
doSomething();
}
switch 语句
缩进
switch 语句的缩进应该在以下两种方案中形成统一:
// case 语句和代码块分别缩进一个层级, 并在每个 case 语句后加一个空行
switch (condition) {
case 1:
doSomething();
break;
case 2:
doSomethingElse();
break;
default:
doNothing();
}
// case 语句不缩进, 且 case 语句后不加空行
switch (condition) {
case 1:
doSomething();
break;
case 2:
doSomethingElse();
break;
default:
doNothing();
}
连续执行 (fall through)
是否允许在 case 代码块结尾不加 break, 使多个 case 连续执行, 是一个备受争议的问题. 各种指南对此没有统一的意见, 但如果确实要使用, 应该保证多个 case 逻辑清晰, 对可能引起误解的部分添加注释.
default
对是否省略没有代码逻辑的 default 语句, 也应该在团队中形成统一.
with 语句
不建议使用 with 语句, 在严格模式 (strict mode) 中, with 语句是被禁止的.
for 循环
对是否允许在 for 循环中使用 continue 语句要形成统一.
for-in 循环
由于 for-in 循环不仅遍历对象的实例属性 (instance property) , 同时还遍历从原型继承来的属性. 因此使用 for-in 遍历自定义对象的属性时, 推荐严格地使用hasOwnProperty()
方法来为其过滤出实例属性:
let prop;
for (prop in object) {
if (object.hasOwnProperty(prop)) {
console.log('Property name is ' + prop);
console.log('Property value is ' + object[prop]);
}
}
在这种情况下, 如果遇到特殊情况, 如查找原型链, 应该补充必要的注释, 以免引起误解.
for-in 循环应该只被用于遍历对象和原型链的键.
第 4 章, 变量, 函数和运算符
变量声明
在 JavaScript 执行过程中, 所有变量声明语句都会提前至函数顶部执行. 即:
function doSomething() {
let result = 10 + value;
let value = 10;
return result;
}
// 以上代码在 JavaScript 看来等于
function doSomething() {
let result;
let value;
result = 10 + value;
value = 10;
return result;
}
因此以上代码返回的结果是一个特殊值 NaN, 因为计算 result 时 value 还未初始化.
以上行为意味着, 将变量声明语句放在函数内任何地方和放在顶部是等价的. 因此, 一种流行的风格是将所有变量声明放在函数顶部执行.
有的标准还推荐使用单声明语句:
function doSomething(items) {
let i, len,
value = 10,
result = value + 10;
for (i=0, len=items.length; i < len; i++) {
doSomethingElse(items[i]);
}
}
使用单声明语句可以使代码更精简.
函数声明
与变量声明一样, 函数声明也会被 JavaScript 引擎提前执行, 即:
doSomething();
function doSomething() {
alert('Hello, World!');
}
// 以上代码在 JavaScript 看来等于
function doSomething() {
alert('Hello, World!');
}
doSomething();
在一个函数当中, 建议以: 变量声明, 函数声明, 逻辑语句的顺序排列语句, 并在变量声明, 每一个函数声明, 和逻辑语句间都添加空行.
同时, 避免在语句块内声明函数.
函数调用间隔
// 不推荐
doSomething (item);
// 推荐
doSomething(item);
匿名函数
声明匿名函数时, 有一种方法可以直接将匿名函数返回值赋予一个变量:
let doSomething = function() {
return {
message: 'Hi'
}
}();
console.log(doSomething); // Object { message: "Hi" }
因为表示赋值的括号位于最后, 因此可能影响代码可读性, 要解决这一问题, 建议把赋值匿名函数用圆括号包裹起来:
// 推荐
let doSomething = (function() {
return {
message: "Hi"
}
})(); // 注意括号
// 或
let doSomething = (function() {
return {
message: "Hi"
}
}()); // 注意括号
严格模式 (strict mode)
严格模式禁止了一些模糊的 JavaScript 用法, 以减少错误. 通过在代码中加入"use strict";
来启用严格模式. 严格模式是有作用域的. 不推荐将"use strict"
用在全局作用域中, 因为可能影响其他没有打算启用严格模式的代码. 如果要对多个函数中应用严格模式, 可以使用匿名函数:
(function() {
"use strict";
function doSomething() {
// something
}
function doSomethingElse() {
// somethin else
}
})();
相等
JavaScript 是弱类型语言, 因此, 严谨起见, 推荐用===
和!==
替代==
和!=
.
eval()
eval()
函数允许将字符串当作 JavaScript 代码执行. 除非万不得已, 不建议使用.
原始包装类型
原始数据类型 - MDN, 不建议使用.