Tgroup

前端开发指南

1. 编码风格指南

建议写法

尾随逗号
多行写法的对象,建议在尾属性后面加上逗号。

1
2
3
4
5
6
7
// Example
var foo = {
bar: "baz",
qux: "quux",
};

var foo = {bar: "baz", qux: "quux"};

不使用 console.log
console.error 和 console.warn 通常用于函数中错误和警告的提示。

1
2
console.error('error');
console.warn('warn');

最佳实践

在类方法中使用 this
如果没有使用到 this,则该写到静态方法中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A {
foo() {
this.bar = "Hello World"; // OK, this is used
}
}

class A {
constructor() {
// OK. constructor is exempt
}
}

class A {
static foo() {
// OK. static methods aren't expected to use this.
}
}

不要使用 alert, confirm 和 prompt
应该使用更加友好的自定义 UI 交互。哪怕为此开发 UI 组件。通常 alert 用于开发调试,那么请在 production 版本将其移除。

不要在 else 块使用 return
如果 If 块包含返回语句,那么 else 块就没有必要了。它的内容可以放在外面的块。

1
2
3
4
5
6
function foo() {
if (x) {
return y;
}
return z;
}

不使用隐式转换
转换值类型的方法有很多,但是有一些可能不好读懂。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var b = !!foo;
var b = ~foo.indexOf(".");
var n = +foo;
var n = 1 * foo;
var s = "" + foo;
foo += ``;

// 建议
var b = Boolean(foo);
var b = foo.indexOf(".") !== -1;
var n = Number(foo);
var n = Number(foo);
var s = String(foo);
foo = String(foo);

不要在循环内放进函数
例如:

1
2
3
4
5
for (let results of data) {
_.each(results, function (value, key) {
// ......
});
}

储存 new 实例
例如:

1
2
3
4
var person = new Person();

// 不建议
new Person();

不要直接修改实参
直接修改实参,会使 arguments 对象发生变化,导致难以预料的错误。

1
2
3
4
5
6
7
function foo(bar) {
bar = 13;
}

function foo(bar) {
bar++;
}

不要使用 script url
例如:

1
location.href = 'javascript: alert("hello")';

不要抛出错误字面值
直接抛出错误字面值,会丢失错误栈。正确写法如下:

1
2
3
4
5
6
7
8
9
10
11
12
throw new Error();

throw new Error("error");

var e = new Error("error");
throw e;

try {
throw new Error("error");
} catch (e) {
throw e;
}

在顶部声明变量
如果你使用的使 let 和 const,可以忽略这里。

1
2
3
4
5
6
7
8
9
10
11
12
function doSomething() {
var first;
var second; //multiple declarations are allowed at the top
if (true) {
first = true;
}
}

function doSomething() {
var i;
for (i=0; i<10; i++) {}
}

变量

不在局部作用域重复声明全局变量

1
2
3
4
5
6
7
8
9
10
11
12
var a = 3;
function b() {
var a = 10;
}

// 允许该情况,因为 if 块中的 a 事先声明了。
if (true) {
let a = 3;
let b = 6;
}

let a = 5;

不要留着没有被使用的变量
留着没有被使用过的变量,浪费内存,且不利于维护。

使用变量前需要先声明
不建议出现以下情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
alert(a);
var a = 10;

f();
function f() {}

function g() {
return b;
}
var b = 1;

{
alert(c);
let c = 1;
}

Node.js and CommonJS

按模块类型分组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// only require declarations (grouping off)
var eventEmitter = require('events').EventEmitter,
myUtils = require('./utils'),
util = require('util'),
bar = require(getBarModuleName());

// only non-require declarations
var foo = 42,
bar = 'baz';

// always valid regardless of grouping because all declarations are of the same type
var foo = require('foo' + VERSION),
bar = require(getBarModuleName()),
baz = require();

不使用合并路径
请使用 path module。因为不同系统类型可能导致无效路径。例如:

1
2
var fullPath = __dirname + "/foo.js";
var fullPath = __filename + "/foo.js";

编码风格

驼峰命名
命名变量的时候,camelcase 和 underscores 用在不同情况下:

1
2
3
4
5
6
7
8
9
10
// camelcase
var myFavoriteColor = "#112C85";
var _myFavoriteColor = "#112C85";
var myFavoriteColor_ = "#112C85";
var MY_FAVORITE_COLOR = "#112C85";

// underscores 用在对象属性
var obj = {
my_pref: 1
};

不使用匿名函数
那么你可以在堆栈里跟踪到函数表达式的名称。

缩进
tab 和 space 缩进都是允许的,但是同一个项目内建议保持一种风格。
我们建议使用 4 spaces。

大写字母开头的构造函数

1
var friend = new Person();

不使用 continue
在循环中滥用 continue 会降低代码的可测试性。建议使用结构化的控制流语句,例如 if。

花括号之间不允许空格

1
2
3
4
5
6
7
8
9
10
11
12
var obj = {'foo': 'bar'};
var obj = {'foo': {'bar': 'baz'}, 'qux': 'quxx'};
var obj = {
'foo': 'bar'
};
var obj = {'foo': 'bar'
};
var obj = {
'foo':'bar'};
var obj = {};
var {x} = y;
import {foo} from 'bar';

其它建议

字符串模版
使用字符串模版连接字符串。

1
2
3
var str = "Hello World!";
var str = `Hello, ${name}!`;
var str = `Time: ${12 * 60 * 60 * 1000}`;

最长代码行
任何语言中非常长的代码行都很难读懂。为了提高可读性和可维护性,许多编码人员制定了一项约定,将代码行数限制在X个字符(传统上是80个字符)。

限制单文件代码行数
有些人认为大文件有代码味道。大型文件往往会做很多事情,并且很难跟上进度、难以维护。虽然现在并没有一个单文件最大行数的标准,但是不应该达到数千行。建议通常从100行到500行。

限制函数最多参数
函数的参数超过一定数量后,可能难以维护。你需要记住这个参数的意义、类型和顺序。因此我们建议当函数参数超过 3 个的时候,改为对象传入。

2. 代码注释规范

编写代码注释的必要性

代码注释能帮助阅读者更好地阅读和理解代码。
良好的代码注释,满足以下两个条件:

  1. 可阅读性,准确而简洁。
  2. 可维护性,易于修改,避免冗余。

注释类型

  1. 单行注释:通常放在代码块上方
  2. 文档类注释:API、类、函数(遵守 JSDOC 规范)
  3. 文件注释:文件头部书写固定格式的注释,注明作者、协议等信息

注释规范

单行注释

1
2
// 获取 App 对象
const APP = getApp()

多行注释

如果注释内容超过一行的时候,需要使用多行注释。多行注释请参考 JSDOC 规范。

1
2
3
4
5
6
7
8
9
10
/**
* Book类,代表一个书本.
* @constructor
* @param {string} title - 书本的标题.
* @param {string} author - 书本的作者.
*/
function Book(title, author) {
this.title=title;
this.author=author;
}

特殊标记

当你解决或者待解决一个缺陷,需要注释的时候。

1
2
3
4
5
6
7
8
9
// @todo: 待完成某个功能
function foo() {
// write me
}

// @fix: 解决了某个问题
function foo() {
// write me
}

注释行上方空一行

1
2
3
4
5
// 注释1
const APP = getApp()

// 注释2
const PREFIX_URL = '...'

注释内容和注释符之间的空格

1
2
// 注释1
const APP = getApp()

3. 代码自释规范

代码自释说明

顾名思义:不需要注释,能够自解释的代码
优秀的代码有优秀的注释。而不友好的代码会给阅读和调试带来困扰,有可能误导后续的开发。因此我们除了提供优秀的注释,可以通过某些编程规范、技术让代码具备自解释的特征。
让代码具备做到自解释需要具备以下三个特征:

  1. 命名
  2. 语法
  3. 结构

命名

描述数值变量

1
2
const elementWidthPx = 
window.getComputedStyle(element, null).getPropertyValue('width');

不使用 a 或者 b 描述变量,计数器除外。
遵循现有的命名规范。例如

1
const element = getElement();

使用动词+对象构成来替代意义模糊的命名法:

1
2
3
4
5
// Bad
function handleFile(){};

// Good
function sendFile(){};

返回值:

1
function getPropertyValue(){};

语法

使用更具语义的表达:

1
2
3
4
5
6
7
// Bad
isFunction && doit();

// Good
if (isFunction) {
doit();
}

使用大写字母+下划线组合的形式命名常量:

1
2
// 地球赤道周长
const EARTH_EQUATOR_LENGTH = 6378.2;

函数应用中减少使用命名模糊的参数:

1
2
3
4
5
// Bad
myThing.setData({ x: 1 }, true);

// Good
myThing.mergeData({ x: 1 });

使用语言自身提供的方法:

1
2
3
4
5
6
7
8
// Bad
let ids = [];
for(let i = 0; i < things.length; i++) {
ids.push(things[i].id);
}

// Good
let ids = things.map(thing => thing.id);

结构

适当的用函数名帮助解释:

1
2
3
4
var width = emToPixels(value);
function emToPixels(ems) {
return (ems - 0.5) * 16;
}

适当用变量帮助表达式解释:

1
2
3
4
var isVisible = el.offsetWidth && el.offsetHeight;
if(!isVisible) {
...
}

如果你认为别人难以明白你的数学表达式:

1
2
3
var multiplier = a * b;
var divisor = c / d;
return multiplier + divisor;

将具备相同功能,有紧密关系的代码分到一组:

1
2
3
4
5
6
var foo = 1;
bar(foo);
quux(foo);
blah()
xyz();
baz(1337);

4. 开发工具

本文使用 Visual Studio Code 配置 ESLint 实践 Javascript 编码规范。

可以使用其它 IDE 或者编辑器,而 .eslintrc 文件是通用的。

配置 VSCode + ESLint

安装 ESLint 扩展
打开 VSCode 面板并在扩展商店搜索 eslint ,通常是搜索结果列表的第一个。

名称 描述 作者
ESLint Integrates ESLint info VS Code Drink Baeumer

生成 .eslintrc.js 配置文件
首先全局安装:

1
sudo npm i eslint -g

然后在硬盘上选择一个位置,执行以下命令,该命令会以询问的方式帮你配置并最后生成一个 .eslintrc.js|json|yaml 文件。

1
eslint --init

覆盖 ESLint 配置
以 Mac OSX 为例,打开 Code-首选项-设置,编辑器会展开两列配置文件。分别是默认设置、用户设置。

默认设置是 VSCode 或者扩展提供的,如果需要修改,在用户设置用相同的键值对覆盖它。

请按下 command+F 打开搜索框,输入 eslint 并找到 "eslint.options":{},在用户设置添加

1
2
3
4
5
6
{
// 其它用户设置...
"eslint.options": {
"configFile": "[path].eslintrc.js" // .eslintrc.js 在硬盘上的路径
}
}

让 ESLint 检查 Vue 单文件组件
第一步全局安装 eslint-plugin-html,让 eslint 支持 Vue 单文件的代码检测。

1
npm i eslint-plugin-html -g

然后打开编辑器的设置,在用户设置修改 eslint 的相关配置,如下:

1
2
3
4
5
6
7
8
9
"eslint.options": {
"configFile": "[path].eslintrc.js",
"plugins": ["html"]
},
"eslint.validate": [
"javascript",
"html",
"vue"
]