* [建议] 一个函数的长度控制在 50 行以内
将过多的逻辑单元混在一个大函数中,易导致难以维护。一个清晰易懂的函数应该完成单一的逻辑单元。复杂的操作应进一步抽取,通过函数的调用来体现流程。
特定算法等不可分割的逻辑允许例外。
```
function syncViewStateOnUserAction() {
if (x.checked) {
y.checked = true;
z.value = '';
}
else {
y.checked = false;
}
if (!a.value) {
warning.innerText = 'Please enter it';
submitButton.disabled = true;
}
else {
warning.innerText = '';
submitButton.disabled = false;
}
}
// 直接阅读该函数会难以明确其主线逻辑,因此下方是一种更合理的表达方式:
function syncViewStateOnUserAction() {
syncXStateToView();
checkAAvailability();
}
function syncXStateToView() {
if (x.checked) {
y.checked = true;
z.value = '';
}
else {
y.checked = false;
}
}
function checkAAvailability() {
if (!a.value) {
displayWarningForAMissing();
}
else {
clearWarnignForA();
}
}
```
* [建议] 一个函数的参数控制在 6 个以内
除去不定长参数以外,函数具备不同逻辑意义的参数建议控制在 6 个以内,过多参数会导致维护难度增大。
某些情况下,如使用 AMD Loader 的 require 加载多个模块时,其 callback 可能会存在较多参数,因此对函数参数的个数不做强制限制。
* [建议] 通过 options 参数传递非数据输入型参数
有些函数的参数并不是作为算法的输入,而是对算法的某些分支条件判断之用,此类参数建议通过一个 options 参数传递。
```
/**
* 移除某个元素
*
* @param {Node} element 需要移除的元素
* @param {boolean} removeEventListeners 是否同时将所有注册在元素上的事件移除
*/
function removeElement(element, removeEventListeners) {
element.parent.removeChild(element);
if (removeEventListeners) {
element.clearEventListeners();
}
}
//上面的函数可以转换为以下方式
/**
* 移除某个元素
* * @param {Node} element 需要移除的元素
* @param {Object} options 相关的逻辑配置
* @param {boolean} options.removeEventListeners 是否同时将所有注册在元素上的事件移除
*/
function removeElement(element, options) {
element.parent.removeChild(element);
if (options.removeEventListeners) {
element.clearEventListeners();
}
}
```
这种模式有几个显著的优势:
* boolean 型的配置项具备名称,从调用的代码上更易理解其表达的逻辑意义。
* 当配置项有增长时,无需无休止地增加参数个数,不会出现 removeElement(element, true, false, false, 3) 这样难以理解的调用代码。
* 当部分配置参数可选时,多个参数的形式非常难处理重载逻辑,而使用一个 options 对象只需判断属性是否存在,实现得以简化。