前端JS规范
变量
命名方式:小驼峰
命名规范:前缀名词
// bad
let setCount = 10
// good
let maxCount = 10
常量
命名方式:全部大写
命名规范:多个单词时使用分隔符_
// bad
const serverErrorCode = {
success: 200,
repeat: 444
}
// good
const SERVER_ERROR_CODE = {
SUCCESS: 200,
REPEAT: 444
}
函数名
命名方式:小驼峰
命名规范:前缀动词
// bad
function wordClass() {}
// good
function saveWordClass() {}
常用动词:can、has、is、load、get、set
类名
命名方式:大驼峰
命名规范:前缀名词
// bad
class person {}
// good
class Person {}
注释
单行
// 单行注释,注意前面的空格
let maxCount = 123
多行
/**
* 多行注释
* /
函数注释
/**
* 函数描述
*
* @param {string} p1 参数1的说明
* @param {string} p2 参数2的说明,比较长
* 那就换行了.
* @param {number=} p3 参数3的说明(可选)
* @return {Object} 返回值描述
*/
function foo(p1, p2, p3) {
var p3 = p3 || 10;
return {
p1: p1,
p2: p2,
p3: p3
};
}
函数
函数行数
- [建议] 一个函数的长度控制在
50
行以内。
将过多的逻辑单元混在一个大函数中,易导致难以维护。一个清晰易懂的函数应该完成单一的逻辑单元。复杂的操作应进一步抽取,通过函数的调用来体现流程。
特定算法等不可分割的逻辑允许例外。
参数设计
- [建议] 一个函数的参数控制在
6
个以内。
除去不定长参数以外,函数具备不同逻辑意义的参数建议控制在
6
个以内,过多参数会导致维护难度增大。
- [建议] 通过
options
参数传递非数据输入型参数。
这种模式有几个显著的优势:
- 当配置项有增长时,无需无休止地增加参数个数,不会出现
removeElement(element, true, false, false, 3)
这样难以理解的调用代码。- 当部分配置参数可选时,多个参数的形式非常难处理重载逻辑,而使用一个 options 对象只需判断属性是否存在,实现得以简化。
空格(prettier自动)
二元运算符两侧必须有一个空格,一元运算符与操作对象之间不允许有空格
jsvar a = !arr.length; a++; a = b + c;
用作代码块起始的左花括号
{
前必须有一个空格jsif (condition) { }
if / else / for / while / function / switch / do / try / catch / finally
关键字后,必须有一个空格在对象创建时,属性中的
:
之后必须有空格,:
之前不允许有空格jsvar obj = { a: 1, b: 2, c: 3 };
函数声明、具名函数表达式、函数调用中,函数名和
(
之间不允许有空格。js// good function funcName() { }
在函数调用、函数声明、括号表达式、属性访问、
if / for / while / switch / catch
等语句中,()
和[]
内紧贴括号部分不允许有空格。js// good callFunc(param1, param2, param3)
单行声明的数组与对象,如果包含元素,
{}
和[]
内紧贴括号部分不允许包含空格。声明包含元素的数组与对象,只有当内部元素的形式较为简单时,才允许写在一行。元素复杂的情况,还是应该换行书写。
js// good var arr1 = [] var arr2 = [1, 2, 3] var obj1 = {} var obj2 = {name: 'obj'} var obj3 = { name: 'obj', age: 20, sex: 1 }
括号
下列关键字后必须有大括号(即使代码块的内容只有一行):if
, else
, for
, while
, do
, switch
, try
, catch
, finally
, with
。
减少嵌套
确定条件不允许时,尽早返回。经典使用场景:校验数据
// bad
if (condition1) {
if (condition2) {
...
}
}
// good
if (!condition1) return
if (!condition2) return
...
减少特定标记值
使用常量进行自解释
// bad
type: 1 // 1代表新增 2代表修改
// good
const MODIFY_TYPE = {
ADD: 1,
EDIT: 2
}
type: MODIFY_TYPE.ADD
表达式
尽可能简洁表达式
// bad
if (name === ''){}
if (collection.length > 0){}
if (notTrue === false){}
// good
if (!name) {}
if (collection.length){}
if (notTrue){}
分支较多处理
对于相同变量或表达式的多值条件,用switch
代替if
。
// bad
let type = typeof variable
if (type === 'object') {
// ......
}
else if (type === 'number' || type === 'boolean' || type === 'string') {
// ......
}
// good
switch (typeof variable) {
case 'object':
// ......
break
case 'number':
case 'boolean':
case 'string':
// ......
break
}
使用变量名自解释
逻辑复杂时,建议使用变量名自解释,而不是晦涩难懂的简写。
// bad
function(value) {
return !helpers.req(value) || this.entity.entVocabularyEntries.filter(item => item.vocabularyEntryName === value).length < 2
}
// good
function(value) {
let entVocabularyList = this.entity.entVocabularyEntries
let repeatCount = entVocabularyList.filter(item => item.vocabularyEntryName === value).length
return !helpers.req(value) || repeatCount < 2
}
使用函数名自解释
遵循单一职责的基础上,可以把逻辑隐藏在函数中,同时使用准确的函数名自解释。
// bad
if (modifyType === MODIFY_TYPE.ADD) {
batchVariableAPI(data).then(() => {
this.closeModal()
this.$toast.show('添加变量成功')
})
} else {
updateVariableAPI(data).then(() => {
this.closeModal()
this.$toast.show('修改变量成功')
})
}
// good
modifyType === MODIFY_TYPE.ADD ? this._insertVariable(data) : this._updateVariable(data)
_insertVariable() {
batchVariableAPI(data).then(() => this._successOperation('添加变量成功'))
}
_updateVariable() {
updateVariableAPI(data).then(() => this._successOperation('修改变量成功'))
}
_successOperation(toastMsg) {
this.closeModal()
this.$toast.show(toastMsg)
}
杂项
- 用'===', '!=='代替'==', '!='
- 不要在内置对象的原型上添加方法,如Array, Date
- 不要声明了变量却不使用
- 变量不要先使用后声明
- 不要在循环内部声明函数
- 对上下文this的引用只能使用'_this', 'that', 'self'其中一个来命名
工具: prettierrc格式化 + eslint校验
- 自动格式化
- 2个缩进
- 最外层使用单引号
- 方法if / else / for / while / function / switch / do / try / catch / finally 关键字后有一个空格
- 自动省略分号