javascript代码整洁之道
来自Robert C. Martin的书,《clean code》. 目标是编写出可读的, 可重用, 可重构的代码。
变量
使用有意义、可读(出声)的变量名
坏: {% codeblock lang:javascript %} const yyyymmdstr = moment().format(‘YYYY/MM/DD’) {% endcodeblock %}
好: {% codeblock lang:javascript %} const now = moment().format(‘YYYY/MM/DD’) {% endcodeblock %}
对同类型的变量使用同样的词
坏: {% codeblock lang:javascript %} getUserInfo() getClientData() getCustomerRecord() {% endcodeblock %}
好: {% codeblock lang:javascript %} getUser() {% endcodeblock %}
使用可以搜索的名字
代码能够被读、被理解、被回忆、被搜索。
坏: {% codeblock lang:javascript %} // whate the heck is 864000000? setTimeout(blastOff, 864000000) {% endcodeblock %}
好: {% codeblock lang:javascript %} const MILLISECONDS_IN_A_DAY = 864000000 setTimeout(blastOff, MILLISECONDS_IN_A_DAY) {% endcodeblock %}
用可解释的变量民
坏: {% codeblock lang:javascript %} const address = “One Infinite Loop, Cupertino 95014”; const cityZipCodeRegex = /^[^,\]+[,\\s]+(.+?)\s*(\d{5})?$/; saveCityZipCode( address.match(cityZipCodeRegex)[1], // 第一个字段是什么 address.match(cityZipCodeRegex)[2] // 第二个字段是什么 ); {% endcodeblock %}
好: {% codeblock lang:javascript %} const address = “One Infinite Loop, Cupertino 95014”; const cityZipCodeRegex = /^[^,\]+[,\\s]+(.+?)\s*(\d{5})?$/; const [, city, zipCode] = address.match(cityZipCodeRegex) || []; saveCityZipCode(city, zipCode); {% endcodeblock %}
避免认知映射
坏:
{% codeblock lang:javascript %}
const locations = [“Austin”, “New York”, “San Francisco”];
locations.forEach(l => {
doStuff();
doSomeOtherStuff();
// …
// …
// …
// Wait, what is l
for again?
dispatch(l);
});
{% endcodeblock %}
好: {% codeblock lang:javascript %} const locations = [“Austin”, “New York”, “San Francisco”]; locations.forEach(location => { doStuff(); doSomeOtherStuff(); // … // … // … dispatch(location); }); {% endcodeblock %}
不要增加额外的上下文前后缀
坏: {% codeblock lang:javascript %} const Car = { carMake: “Honda”, carModel: “Accord”, carColor: “Blue” };
function paintCar(car) {
car.carColor = "Red";
}
{% endcodeblock %}
好: {% codeblock lang:javascript %} const Car = { make: “Honda”, model: “Accord”, color: “Blue” };
function paintCar(car) {
car.color = "Red";
}
{% endcodeblock %}
使用参数默认值而不是短路条件
坏: {% codeblock lang:javascript %} function createMicrobrewery(name) { const breweryName = name || “Hipster Brew Co.”; // … } {% endcodeblock %}
好: {% codeblock lang:javascript %} function createMicrobrewery(name = “Hipster Brew Co.”) { // … } {% endcodeblock %}
函数
函数参数最好是2个以下
坏: {% codeblock lang:javascript %} function createMenu(title, body, buttonText, cancellable) { // … } {% endcodeblock %}
好: {% codeblock lang:javascript %} function createMenu({ title, body, buttonText, cancellable }) { // … }
createMenu({
title: "Foo",
body: "Bar",
buttonText: "Baz",
cancellable: true
});
{% endcodeblock %}
函数应该做一件事
函数名应该指明函数做了什么
函数内容应该在同一个抽象层级
清理重复代码
用Object.assign设置默认对象
坏: {% codeblock lang:javascript %} const menuConfig = { title: null, body: “Bar”, buttonText: null, cancellable: true };
function createMenu(config) {
config.title = config.title || "Foo";
config.body = config.body || "Bar";
config.buttonText = config.buttonText || "Baz";
config.cancellable =
config.cancellable !== undefined ? config.cancellable : true;
}
createMenu(menuConfig);
{% endcodeblock %}
好: {% codeblock lang:javascript %} const menuConfig = { title: “Order”, // User did not include ‘body’ key buttonText: “Send”, cancellable: true };
function createMenu(config) {
config = Object.assign(
{
title: "Foo",
body: "Bar",
buttonText: "Baz",
cancellable: true
},
config
);
// config now equals: {title: "Order", body: "Bar", buttonText: "Send", cancellable: true}
// ...
}
{% endcodeblock %}
不要有flag作为函数参数*
坏:
{% codeblock lang:javascript %}
function createFile(name, temp) {
if (temp) {
fs.create(./temp/${name}
);
} else {
fs.create(name);
}
}
{% endcodeblock %}
好: {% codeblock lang:javascript %} function createFile(name) { fs.create(name); }
function createTempFile(name) {
createFile(`./temp/${name}`);
}
{% endcodeblock %}
避免副作用
参考函数式编程
不要写全局函数*
偏好函数式编程*
包装条件*
坏: {% codeblock lang:javascript %} if (fsm.state === “fetching” && isEmpty(listNode)) { // … } {% endcodeblock %}
好: {% codeblock lang:javascript %} function shouldShowSpinner(fsm, listNode) { return fsm.state === “fetching” && isEmpty(listNode); }
if (shouldShowSpinner(fsmInstance, listNodeInstance)) {
// ...
}
{% endcodeblock %}
避免条件非*
坏: {% codeblock lang:javascript %} function isDOMNodeNotPresent(node) { // … }
if (!isDOMNodeNotPresent(node)) {
// ...
}
{% endcodeblock %}
好: {% codeblock lang:javascript %} function isDOMNodePresent(node) { // … }
if (isDOMNodePresent(node)) {
// ...
}
{% endcodeblock %}
避免条件
减少if/switch等的使用,通过别的地方的设计。
避免检查类型
删除dead code
其他