JavaScript 编码规范
0 关于 ES5
表单设计器里面的 JS 代码都是会直接在浏览器运行的,如果不确定浏览器的支持情况,统一用 ES5 的写法是最安全的。
-
0.1
recommendedES5 中的变量声明。使用
var进行声明:// good
var foo = 'foo';需注意,
var声明的变量不是块作用域而是函数作用域:// 将打印 2, 2, 2,而非 0, 1, 2
for (var i = 0; i < 3; ++i) {
var iteration = i;
setTimeout(function() { console.log(iteration); }, i * 1000);
}另外,
var声明的变量会被提升到其作用域顶部:// 变量声明会被提升到函数顶部,但赋值不会被提升
function example() {
console.log(declaredButNotAssigned); // => undefined
console.log(notDeclared); // => throws a ReferenceError
var declaredButNotAssigned = true;
}即便如此,我们还是推荐在变量使用前再进行声明,而不是统一在作用域开始处声明,以增强可读性。当然,如果你担心声明提升问题会带来隐患,也可以选择统一在作用域开始处进行声明。
不要在声明前就使用变量,这样做可能给人带来疑惑和隐患。eslint:
no-use-before-define// bad
console.log(foo); // => undefined
var foo = 'foo';
// good
var foo = 'foo';
console.log(foo); // => foo -
0.2
referenced使用 Array 的 slice 方法进行数组复制和类数组对象转换。数组复制:
var items = [1, 2, 3];
// bad
var itemsCopy = [];
for (var i = 0; i < items.length; i++) {
itemsCopy[i] = items[i];
}
// good
var itemsCopy = items.slice();将类数组对象转换成数组:
function trigger() {
var args = Array.prototype.slice.call(arguments);
// ...
} -
0.3
recommended不要使用保留字作为对象的属性名。不要使用保留字作为对象的属性名,它们在 IE8 中不工作
// bad
var superman = {
class: 'alien',
default: { clark: 'kent' },
private: true
};
// good
var superman = {
type: 'alien',
defaults: { clark: 'kent' },
hidden: true
};
1 编码风格
编码风格系统已经自带格式化规范,写完代码过后右键格式化(Format Document)。
如图:

2 语言特性
2.1 变量声明
-
2.1.1
mandatory一条声明语句声明一个变量。eslint: one-var这样做更易于追加新的声明语句(你不需要总去把最后的
;改成,了),也更易于进行单步调试。// bad
const foo = 1,
bar = 2;
// good
const foo = 1;
const bar = 2; -
2.1.2
mandatory声明的变量必须被使用。eslint: no-unused-vars声明而未使用的变量、表达式可能带来潜在的问题,也会给维护者造成困扰,应将它们删除。
// bad - 未使用变量 foo
const foo = 1;
// good
const foo = 1;
doSomethingWith(foo);
// bad - 只修改变量不认为是被使用
let bar = 1;
bar = 2;
bar += 1;
// good
let bar = 1;
bar = 2;
bar += 1;
doSomethingWith(bar);
// bad - 未使用参数 y
function getX(x, y) {
return x;
}
// good
function getXPlusY(x, y) {
return x + y;
} -
2.1.3
referenced哪里使用,哪里声明。在变量被使用前再进行声明,而不是统一在块开始处进行声明。
ES6 提供的
let和const是块级作用域,不存在类似var的声明提升的问题。因此我们可以把声明写在更合理的地方(一般是变量被使用前),而不是统一在块开始处进行声明。// bad - 如果权限校验(checkUserPermission)失败,fetchData 是不必要的
function getData(id) {
const data = fetchData(id);
if (!checkUserPermission()) {
return false;
}
if (data.foo === 'bar') {
// ...
}
return data;
}
// good
function getData(id) {
if (!checkUserPermission()) {
return false;
}
const data = fetchData(id);
if (data.foo === 'bar') {
// ...
}
return data;
} -
2.1.4
mandatory变量不要与外层作用域已存在的变量同名。eslint: no-shadow如果变量与外层已存在变量同名,会降低可读性,也会导致内层作用域无法读取外层作用域的同名变量。
// bad
const foo = 1;
if (someCondition) {
const foo = 2;
console.log(foo); // => 2
}
// good
const foo = 1;
if (someCondition) {
const bar = 2;
console.log(bar); // => 2
console.log(foo); // => 1
} -
2.1.5
mandatory不要重复声明变量和函数。eslint: no-redeclare在 ES5 中,尽管使用
var重复声明不会报错,但这样做会令人疑惑,降低程序的可维护性。同理,函数的声明也不要与已存在的变量和函数重名:// bad
var a = 'foo';
var a = 'bar';
function a() {}
console.log(a); // => 'bar'
// good
var a = 'foo';
var b = 'bar';
function c() {}
console.log(a); // => 'foo'
// bad - arg 已作为函数参数声明
function myFunc(arg) {
var arg = 'foo';
console.log(arg);
}
myFunc('bar'); // => 'foo'
// good
function myFunc(arg) {
var otherName = 'foo';
console.log(arg);
}
myFunc('bar'); // => 'bar'在 ES6 中,使用
const或let重复声明变量会直接报错:// bad
const a = 'foo';
function a() {} // => Uncaught SyntaxError: Identifier 'a' has already been declared
// good
const a = 'foo';
function b() {}
// bad - arg 已作为函数参数声明
function myFunc(arg) {
const arg = 'foo';
console.log(arg);
}
myFunc('bar'); // => Uncaught SyntaxError: Identifier 'arg' has already been declared
// good
function myFunc(arg) {
const otherName = 'foo';
console.log(arg);
}
myFunc('bar'); // => 'bar'
2.2 原始类型
JS的数据类型包括 7 种原始类型(primitive type),即 Boolean, Null, Undefined, Number, String, Symbol (ES6 新定义), BigInt(ES11新定义),以及 Object 类型,了解更多。这个章节主要介绍原始类型相关的规约。
-
2.2.1
mandatory不要使用 new Number/String/Boolean。eslint: no-new-wrappers使用 new Number/String//Boolean 声明不会有任何好处,还会导致变量成为
object类型,可能引起 bug。// bad
const num = new Number(0);
const str = new String('foo');
const bool = new Boolean(false);
console.log(typeof num, typeof str, typeof bool); // => object, object, object
if (num) { // true(对象相当于 true)
}
if (bool) { // true(对象相当于 true)
}
// good
const num = 0;
const str = 'foo';
const bool = false;
console.log(typeof num, typeof str, typeof bool); // => number, string, boolean
if (num) { // false(0 相当于 false)
}
if (bool) { // false
} -
2.2.2
recommended类型转换。【数字】使用
Number()或parseInt():const str = '1';
// bad
const num = +str;
const num = str >> 0;
const num = new Number(str);
// good
const num = Number(str);
// good
const num = parseInt(str, 10);【字符串】使用
String():const num = 1;
// bad
const str = new String(num); // typeof str is "object" not "string"
const str = num + ''; // invokes num.valueOf()
const str = num.toString(); // isn’t guaranteed to return a string
// good
const str = String(num);【布尔值】使用
!!:const age = 0;
// bad
const hasAge = new Boolean(age);
const hasAge = Boolean(age);
// good
const hasAge = !!age; -
2.2.3
recommended使用 parseInt() 方法时总是带上基数。eslint: radixparseInt方法的第一个参数是待转换的字符串,第二个参数是转换基数。当第二个参数省略时,parseInt会根据第一个参数自动判断基数:- 如果以 0x 开头,则使用 16 作基数
- 如果以 0 开头,则使用 8 作基数。正是这条规则经常导致错误,ES5 规范中直接将这条规则移除,即 ES5 及之后的执行环境以 0 开头也会使用 10 作为基数
- 其他情况则使用 10 作基数
虽然从 ES5 开始就移除了自动以 8 作基数的规则,但有时难以保证所有的浏览器和 JS 执行环境都支持了这一特性。了解更多
因此,推荐始终给
parseInt()方法加上基数,除非可以保证代码的执行环境不受上述特性的影响。// bad
parseInt("071"); // => ES5 前的执行环境中得到的是 57
// good
parseInt("071", 10); // => 71 -
2.2.4
mandatory避免不必要的布尔类型转换。eslint: no-extra-boolean-cast在
if等条件语句中,将表达式的结果强制转换成布尔值是多余的:// bad
if (!!foo) {
// ...
}
while (!!foo) {
// ...
}
const a = !!flag ? b : c;
// good
if (foo) {
// ...
}
while (foo) {
// ...
}
const a = flag ? b : c; -
2.2.5 字符串
-
2.2.5.1
mandatory字符串优先使用单引号。eslint: quotes// bad
const name = "tod";
const name = `tod`; // 模板字符串中应包含变量或换行,否则需用单引号
// good
const name = 'tod'; -
2.2.5.2
recommended使用模板字符串替代字符串拼接。eslint: prefer-template模板字符串让代码更简洁,可读性更强
// bad
function getDisplayName({ nickName, realName }) {
return nickName + ' (' + realName + ')';
}
// good
function getDisplayName({ nickName, realName }) {
return `${nickName} (${realName})`;
} -
2.2.5.3
mandatory禁止不必要的转义字符。no-useless-escape转义字符会大大降低代码的可读性,因此尽量不要滥用它们。
// bad
const foo = '\'this\' \i\s \"quoted\"';
// good
const foo = '\'this\' is "quoted"';
const foo = `'this' is "quoted"`;
2.3 数组
-
2.3.1
mandatory使用字面量创建数组。eslint: no-array-constructor不要使用
new Array()和Array()创建数组,除非为了构造某一长度的空数组。// bad
const a = new Array(1, 2, 3);
const b = Array(1, 2, 3);
// good
const a = [1, 2, 3];
const b = new Array(500); // 构造长度为 500 的空数组 -
2.3.2
mandatory某些数组方法的回调函数中必须包含 return 语句。eslint: array-callback-return以下数组方法:
map,filter,from,every,find,findIndex,reduce,reduceRight,some,sort的回调函数中必须包含return语句,否则可能会产生误用或错误。一个常见的误用是,本该用
forEach的场景却用了map:// 欲将 ['a', 'b', 'c'] 转换成 {a: 0, b: 1, c: 2}
const myArray = ['a', 'b', 'c'];
const myObj = {};
// bad - map 应用于构建一个新数组,单纯想遍历数组应使用 forEach
myArray.map((item, index) => {
myObj[item] = index;
});
// good
myArray.forEach((item, index) => {
myObj[item] = index;
});某些方法漏掉
return还可能引起错误:// 欲将 ['a', 'b', 'c'] 转换成 {a: 0, b: 1, c: 2}
const myArray = ['a', 'b', 'c'];
// bad => Uncaught TypeError: Cannot set property 'b' of undefined
const myObj = myArray.reduce((memo, item, index) => {
memo[item] = index;
}, {});
// good
const myObj = myArray.reduce((memo, item, index) => {
memo[item] = index;
return memo;
}, {});
2.4 对象
-
2.4.1
mandatory使用字面量创建对象。eslint: no-new-object// bad
const obj = new Object();
// good
const obj = {}; -
2.4.2
mandatory对象的属性名不要用引号包裹,除非包含特殊字符。eslint: quote-props这样更加简洁,也有助于语法高亮和一些 JS 引擎的优化。
// bad
const bad = {
'foo': 3,
'bar': 4,
'data-blah': 5,
'one two': 12,
};
// good
const good = {
foo: 3,
bar: 4,
'data-blah': 5,
'one two': 12,
}; -
2.4.3
mandatory优先使用 . 访问对象的属性。eslint: dot-notation这样可以提高代码可读性。
[]仅应在访问动态属性名或包含特殊字符的属性名时被使用。const obj = {
active: true,
[getDynamicKey()]: 'foo',
'data-bar': 'bar',
};
// bad
const isActive = obj['active'];
// good
const isActive = obj.active;
const foo = obj[getDynamicKey()];
const bar = obj['data-bar']; -
2.4.4
mandatory不要直接在对象上调用 Object.prototypes 上的方法。eslint: no-prototype-builtins不要直接在对象上调用
Object.prototypes上的方法,例如hasOwnProperty、propertyIsEnumerable、isPrototypeOf。这些方法可能会被对象上的属性覆盖,导致错误:
const obj = {
foo: 'foo',
hasOwnProperty: false,
};
const objNull = Object.create(null);
// bad => Uncaught TypeError: obj.hasOwnProperty is not a function
console.log(obj.hasOwnProperty('foo'));
console.log(objNull.hasOwnProperty('foo'));
// good
console.log(Object.prototype.hasOwnProperty.call(obj, 'foo'));
console.log(Object.prototype.hasOwnProperty.call(objNull, 'foo'));
2.5 函数
-
2.5.1
mandatory不要在块中使用函数声明。eslint: no-inner-declarations在非函数块(如
if、while等)中,不要使用函数声明:// bad - 函数声明不是块作用域而是函数作用域,因此在块外也能使用函数,容易引起误解
if (true) {
function test() {
console.log('test');
}
}
test(); // => test
// good - 函数表达式可以清晰地说明函数能否在块外使用
// 不能在块外使用
if (true) {
const test = function () {
console.log('test');
};
}
test(); // => Uncaught ReferenceError: test is not defined
// 能在块外使用
let test;
if (true) {
test = function () {
console.log('test');
};
}
test(); // => test -
2.5.2
recommended不要修改函数参数。eslint: no-param-reassign不要修改引用类型的参数,这可能导致作为入参的原变量发生变化:
// bad
const f1 = function f1(obj) {
obj.key = 1;
}
const originalObj = { key: 0 };
f1(originalObj);
console.log(originalObj); // => { key: 1 }
// good
const f2 = function f2(obj) {
const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
}更不要给参数重新赋值,这可能导致意外的行为和内核优化问题:
// bad
function foo(bar, baz) {
if (!baz) {
bar = 1;
}
}
// good
function foo(bar, baz) {
let qux = bar;
if (!baz) {
qux = 1;
}
} -
2.5.3
mandatory将立即执行函数表达式(IIFE)用小括号包裹。eslint: wrap-iifeIIFE 是一个独立的执行单元,将它用小括号包裹可以更清晰的体现这点。需要提醒的是,由于 ES6 模块语法的引入,你可能不再需要使用 IIFE 了。
(function () {
console.log('Welcome to the Internet. Please follow me.');
}()); -
2.5.4
referenced函数的复杂度不应过高。eslint: complexity过高的复杂度意味着代码难以维护和测试。我们推荐函数的复杂度不要超过以下阈值:
- 圈复杂度不超过 10
- 认知复杂度不超过 15
2.6 操作符
-
2.6.1
recommended使用严格相等运算符。eslint: eqeqeq非严格相等运算符(
==和!=)会在比较前将被比较值转换为相同类型,对于不熟悉 JS 语言特性的人来说,这可能造成不小的隐患。了解更多因此,一般情况下我们应该使用严格比较运算符(
===和!==)进行比较。如果要比较的两个值类型不同,应该显性地将其转换成相同类型再进行严格比较,而不是依赖于==和!=的隐式类型转换。const id = '83949';
// bad - 为了兼容 id 可能是字符串的情况,而有意使用 == 与数字比较
if (id == 83949) {
// do something
}
// good - 如果 id 可能是字符串,应该先将其进行类型转换,再使用 === 进行比较
if (Number(id) === 83949) {
// do something
} -
2.6.2
mandatory不要使用一元自增自减运算符。eslint: no-plusplus不要使用一元自增自减运算符(
++和--),除非在for循环条件中。++和--会带来值是否会提前变化带来的理解成本,也可能因为自动添加分号机制导致一些错误,因此我们推荐使用num += 1来代替num++。但出于习惯,在for循环的条件中依然可以使用自增自减运算符。let num = 1;
// bad
num++;
--num;
// good
num += 1;
num -= 1; -
2.6.3
mandatory不要使用 void 运算符。eslint: no-void在很老版本的 JS 中,
undefined值是可变的,因此使用void语句一般是用来得到一个undefined值。而在新版本的 JS 中,上面的问题已不复存在。因此出于程序可读性的考虑,禁止使用void运算符。// bad
const foo = void 0;
// good
const foo = undefined; -
2.6.4
mandatory避免嵌套的三元表达式。eslint: no-nested-ternary嵌套的三元表达式会降低代码可读性。
// bad
const foo = bar ? baz : qux === quxx ? bing : bam;
// good
const qu = qux === quxx ? bing : bam;
const foo = bar ? baz : qu; -
2.6.5
mandatory避免不必要的三元表达式。eslint: no-unneeded-ternary// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;
// good
const foo = a || b;
const bar = !!c;
const baz = !c; -
2.6.6
mandatory混合使用多种操作符时,用小括号包裹分组。eslint: no-mixed-operators这可以更清晰地表达代码意图,提高可读性。四则运算符(
+,-,*,/)可以不包裹,因为大多数人熟知它们的优先级。// bad
const foo = a && b < 0 || c > 0 || d + 1 === 0;
// good
const foo = (a && b < 0) || c > 0 || (d + 1 === 0);
// bad
const bar = a ** b - 5 % d;
// good
const bar = (a ** b) - (5 % d);
// bad - 有人可能会误以为执行顺序是 (a || b) && c
if (a || b && c) {
return d;
}
// good
if (a || (b && c)) {
return d;
}
// good - 四则运算可以不用小括号包裹
const bar = a + b / c * d;
2.7 控制语句
-
2.7.1
mandatoryswitch 语句中的 case 需要以 break 结尾。eslint: no-fallthrough// bad
switch(foo) {
case 1:
doSomething();
case 2:
doSomethingElse();
default:
doSomething();
}
// good
switch(foo) {
case 1:
doSomething();
break;
case 2:
doSomethingElse();
break;
default:
doSomething();
} -
2.7.2
recommendedswitch 语句需要始终包含 default 分支。eslint: default-case在使用
switch语句时,有时会出现因开发者忘记设置default而导致错误,因此建议总是给出default。如果有意省略default,请在switch语句末尾用// no default注释指明:// bad
let foo;
switch (bar) {
case 1:
foo = 2;
break;
}
// good
let foo;
switch (bar) {
case 1:
foo = 2;
break;
default:
foo = 0;
}
// good - 如果有意省略 default,请在 switch 语句末尾用 `// no default` 注释指明
let foo = 0;
switch (bar) {
case 1:
foo = 2;
break;
// no default
} -
2.7.3
referencedswitch 语句应包含至少 3 个条件分支。switch语句在有许多条件分支的情况下可以使代码结构更清晰。但对于只有一个或两个条件分支的情况,更适合使用if语句,if语句更易于书写和阅读。// bad
let foo;
switch (bar) {
case 1:
foo = 2;
break;
default:
foo = 0;
}
// good
let foo;
if (bar === 1) {
foo = 2;
} else {
foo = 0;
} -
2.7.4
referenced控制语句的嵌套层级不要过深。eslint: max-depth控制语句的嵌套层级不要超过 4 级,否则将难以阅读和维护:
// bad
if (condition1) {
// depth = 1
if (condition2) {
// depth = 2
for (let i = 0; i < 10; i++) {
// depth = 3
if (condition4) {
// depth = 4
if (condition5) {
// bad - depth = 5
}
return;
}
}
}
} -
2.7.5
mandatoryfor 循环中的计数器应朝着正确方向移动。eslint: for-direction当
for循环中更新子句的计数器朝着错误的方向移动时,循环的终止条件将永远无法达到,这会导致死循环的出现。这时要么是程序出现了错误,要么应将for循环改为while循环。// bad
for (let i = 0; i < length; i--) {
// do something
}
// good
for (let i = 0; i < length; i++) {
// do something
} -
2.7.6
recommendedfor-in 循环中需要对 key 进行验证。eslint: guard-for-in使用
for-in循环时需要避免对象从原型链上继承来的属性也被遍历出来,因此保险的做法是对 key 是否是对象自身的属性进行验证:// bad
for (const key in foo) {
doSomething(key);
}
// good
for (const key in foo) {
if (Object.prototype.hasOwnProperty.call(foo, key)) {
doSomething(key);
}
} -
2.7.7
referenced如果一个 if 语句的结果总是返回一个 return 语句,那么最后的 else 是不必要的。eslint: no-else-return// bad
function foo() {
if (x) {
return x;
} else {
return y;
}
}
// good
function foo() {
if (x) {
return x;
}
return y;
} -
2.7.8
referenced条件表达式的计算结果。条件表达式(例如
if语句的条件)的值为通过抽象方法ToBoolean进行强制转换所得,计算结果遵守下面的规则:- 对象、数组 被计算为 true
- Undefined 被计算为 false
- Null 被计算为 false
- 布尔值 被计算为 布尔的值
- 数字 如果是 +0、-0 或 NaN 被计算为 false,否则为 true
- 字符串 如果是空字符串
''被计算为 false,否则为 true
if ({}) { // => true
}
if ([]) { // => true
}
if (0) { // => false
}
if ('0') { // => true
}
if ('') { // => false
}
2.8 其他
-
2.8.1
mandatory禁止使用 eval。eslint: no-evaleval语句存在安全风险,可能导致注入攻击。// bad
const obj = { x: 'foo' };
const key = 'x';
const value = eval('obj.' + key);
// good
const obj = { x: 'foo' };
const key = 'x';
const value = obj[key]; -
2.8.2
mandatory禁止使用 debugger。eslint: no-debuggerdebugger语句会让程序暂停,并在当前位置开启调试器。它通常在程序调试阶段使用,不应发布到线上。// bad
function isTruthy(x) {
debugger;
return Boolean(x);
} -
2.8.3
recommended禁止使用 alert。eslint: no-alertalert语句会使浏览器弹出原生警告框,这可能让人感觉你的程序出错了。如果需要对用户弹出警告信息,好的做法是使用第三方的弹窗组件或自己定义警告框样式。同理,confirm和prompt语句也不应被使用。// bad
alert('Oops!');
// good - 使用自定义的 Alert 组件
Alert('Oops!'); -
2.8.4
recommended生产环境禁止使用 console。eslint: no-consoleconsole语句通常在调试阶段使用,发布上线前,应该去掉代码里所有的console语句。// bad
console.log('Some debug messages..'); -
2.8.5
mandatory禁止对原生对象或只读的全局对象进行赋值。eslint: no-global-assignJS 执行环境中会包含一些全局变量和原生对象,如浏览器环境中的
window,node 环境中的global、process,Object,undefined等。除了像window这样的众所周知的对象,JS 还提供了数百个内置全局对象,你可能在定义全局变量时无意对它们进行了重新赋值,因此最好的做法是不要定义全局变量。// bad
window = {};
Object = null;
undefined = 1;
3 注释
注释的目的:提高代码的可读性,从而提高代码的可维护性 注释的原则:如无必要,勿增注释;如有必要,尽量详尽
-
3.1
recommended单行注释使用 //。注释应单独一行写在被注释对象的上方,不要追加在某条语句的后面:
// bad
const active = true; // is current tab
// good
// is current tab
const active = true;注释行上方需要有一个空行(除非注释行上方是一个块的顶部),以增加可读性:
// bad - 注释行上方需要一个空行
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
// good
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
// bad - 注释行上面是一个块的顶部时不需要空行
function getType() {
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
// good
function getType() {
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
} -
3.2
recommended多行注释使用 /** ... */,而不是多行的 //。// bad
// make() returns a new element
// based on the passed in tag name
function make(tag) {
// ...
return element;
}
// good
/**
* make() returns a new element
* based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
} -
3.3
mandatory注释内容和注释符之间需要有一个空格。eslint: spaced-comment注释内容和注释符之间需要有一个空格,以增加可读性:
// bad
//is current tab
const active = true;
// good
// is current tab
const active = true;
// bad
/**
*make() returns a new element
*based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}
// good
/**
* make() returns a new element
* based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
} -
3.4
referenced合理使用特殊注释标记。eslint: no-warning-comments有时我们发现某个可能的 bug,但因为一些原因还没法修复;或者某个地方还有一些待完成的功能,这时我们需要使用相应的特殊标记注释来告知未来的自己或合作者。最常用的特殊标记有两种:
// FIXME: 说明问题是什么// TODO: 说明还要做什么或者问题的解决方案
一个我们不愿看到却很普遍的情况是,我们给代码标记
FIXME或TODO后却一直没找到时间处理。所以当你做了特殊标记,你应该为它负责,在某个时间把它解决。class Calculator extends Abacus {
constructor() {
super();
// FIXME: shouldn’t use a global here
total = 0;
// TODO: total should be configurable by an options param
this.total = 0;
}
} -
3.5
referenced文档类注释使用 jsdoc 规范。文档类注释,如函数、类、文件、事件等,推荐使用 jsdoc 规范或类 jsdoc 的规范。
例如:
/**
* Book类,代表一个书本.
* @constructor
* @param {string} title - 书本的标题.
* @param {string} author - 书本的作者.
*/
function Book(title, author) {
this.title = title;
this.author = author;
}
Book.prototype = {
/**
* 获取书本的标题
* @returns {string|*}
*/
getTitle() {
return this.title;
},
/**
* 设置书本的页数
* @param pageNum {number} 页数
*/
setPageNum(pageNum) {
this.pageNum = pageNum;
},
}; -
3.6
referenced无用的代码注释应被即时删除。无用的注释代码会使程序变得臃肿并降低可读性,应被即时删除。你可以通过版本控制系统找回被删除的代码。
4 命名
-
4.1
referenced使用小驼峰(camelCase)命名原始类型、对象、函数、实例。camelcase// bad
const this_is_my_string = 'foo';
const this_is_my_object = {};
function this_is_my_function() {}
// good
const thisIsMyString = 'foo';
const thisIsMyObject = {};
function thisIsMyFunction() {} -
4.2
mandatory使用大驼峰(PascalCase)命名类和构造函数。eslint: new-cap// bad
function user(options) {
this.name = options.name;
}
const bad = new user({
name: 'nope',
});
// good
class User {
constructor(options) {
this.name = options.name;
}
}
const good = new User({
name: 'yup',
}); -
4.3
referenced命名不要以下划线开头或结尾。eslint: no-underscore-dangleJS 没有私有属性或私有方法的概念,这样的命名可能会让人误解。
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
this._firstName = 'Panda';
// good
this.firstName = 'Panda';