每个开发者都遇到过"意大利面条"式的 JS 代码:混乱的缩进、随意的命名、混杂的逻辑。本文将通过实际案例,展示如何将混乱的代码变得优雅。
案例一:压缩代码还原
原始代码
var a=function(b,c){var d=[];for(var e=0;e<b.length;e++){if(b[e].type===c){d.push(b[e])}}return d};
第一步:格式化
var a = function(b, c) {
var d = [];
for (var e = 0; e < b.length; e++) {
if (b[e].type === c) {
d.push(b[e]);
}
}
return d;
};
第二步:重命名变量
var filterByType = function(items, type) {
var result = [];
for (var i = 0; i < items.length; i++) {
if (items[i].type === type) {
result.push(items[i]);
}
}
return result;
};
第三步:现代化重构
const filterByType = (items, type) => {
return items.filter(item => item.type === type);
};
案例二:回调地狱优化
原始代码
function loadUser(id, callback) {
getUser(id, function(user) {
getPosts(user.id, function(posts) {
getComments(posts[0].id, function(comments) {
callback({
user: user,
posts: posts,
comments: comments
});
});
});
});
}
第一步:格式化并理解逻辑
function loadUser(id, callback) {
getUser(id, function(user) {
getPosts(user.id, function(posts) {
getComments(posts[0].id, function(comments) {
callback({
user: user,
posts: posts,
comments: comments
});
});
});
});
}
第二步:Promise 化
function loadUser(id) {
return getUser(id)
.then(user => {
return getPosts(user.id)
.then(posts => {
return getComments(posts[0].id)
.then(comments => {
return { user, posts, comments };
});
});
});
}
第三步:async/await 重构
async function loadUser(id) {
const user = await getUser(id);
const posts = await getPosts(user.id);
const comments = await getComments(posts[0].id);
return { user, posts, comments };
}
案例三:混乱的条件逻辑
原始代码
function processOrder(o){if(o){if(o.status==1){if(o.items){if(o.items.length>0){var t=0;for(var i=0;i<o.items.length;i++){t+=o.items[i].price}if(t>0){if(o.coupon){t=t*0.9}o.total=t;save(o);return true}}}}}return false}
第一步:格式化
function processOrder(o) {
if (o) {
if (o.status == 1) {
if (o.items) {
if (o.items.length > 0) {
var t = 0;
for (var i = 0; i < o.items.length; i++) {
t += o.items[i].price;
}
if (t > 0) {
if (o.coupon) {
t = t * 0.9;
}
o.total = t;
save(o);
return true;
}
}
}
}
}
return false;
}
第二步:提前返回,减少嵌套
function processOrder(order) {
if (!order || order.status !== 1) return false;
if (!order.items || order.items.length === 0) return false;
let total = 0;
for (let i = 0; i < order.items.length; i++) {
total += order.items[i].price;
}
if (total <= 0) return false;
if (order.coupon) {
total *= 0.9;
}
order.total = total;
save(order);
return true;
}
第三步:函数拆分
function processOrder(order) {
if (!isValidOrder(order)) return false;
const total = calculateTotal(order.items);
if (total <= 0) return false;
order.total = applyDiscount(total, order.coupon);
save(order);
return true;
}
function isValidOrder(order) {
return order
&& order.status === 1
&& order.items
&& order.items.length > 0;
}
function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.price, 0);
}
function applyDiscount(total, coupon) {
return coupon ? total * 0.9 : total;
}
案例四:重复代码消除
原始代码
// 处理用户数据
function processUserData(data) {
var result = [];
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (item.active) {
result.push({
id: item.id,
name: item.name.toUpperCase(),
email: item.email.toLowerCase(),
joined: new Date(item.joinedAt)
});
}
}
return result;
}
// 处理订单数据
function processOrderData(data) {
var result = [];
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (item.active) {
result.push({
id: item.id,
product: item.product.toUpperCase(),
customer: item.customer.toLowerCase(),
ordered: new Date(item.orderedAt)
});
}
}
return result;
}
重构:提取公共逻辑
function processActiveItems(data, transform) {
return data
.filter(item => item.active)
.map(transform);
}
// 使用
const users = processActiveItems(userData, item => ({
id: item.id,
name: item.name.toUpperCase(),
email: item.email.toLowerCase(),
joined: new Date(item.joinedAt)
}));
const orders = processActiveItems(orderData, item => ({
id: item.id,
product: item.product.toUpperCase(),
customer: item.customer.toLowerCase(),
ordered: new Date(item.orderedAt)
}));
美化流程
1. 格式化
使用工具自动格式化,建立基础结构。
2. 理解逻辑
阅读代码,理解每部分的功能。
3. 重命名
将无意义的变量名改为有意义的名称。
4. 简化结构
- 减少嵌套层级
- 使用提前返回
- 拆分大函数
5. 消除重复
提取公共逻辑,避免代码重复。
6. 现代化
使用 ES6+ 语法重构:
- 箭头函数
- 解构赋值
- 模板字符串
- async/await
7. 添加注释
为复杂逻辑添加注释,说明"为什么"。
工具辅助
自动化重构工具
# 使用 jscodeshift 进行代码转换
npx jscodeshift -t transform.js src/
# 使用 lebab 将 ES5 转为 ES6
npx lebab src/ -o src-es6/ --transform arrow,let,template
代码质量工具
# ESLint 自动修复
npx eslint --fix src/
# Prettier 格式化
npx prettier --write src/
最佳实践
- 小步迭代:不要一次性重构整个文件
- 测试覆盖:确保重构不破坏功能
- 版本控制:每次重构单独提交
- 代码审查:让同事审查重构代码
- 文档更新:更新相关文档和注释
总结
从混乱到优雅不是一蹴而就的。通过格式化、理解、重命名、简化、消除重复、现代化等步骤,可以逐步将混乱的代码变得优雅。记住:代码是写给人看的,只是顺便让机器执行。