/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}
GitHub Copilot Chat:用对话方式让 AI 帮你重构代码

一、重构——AI 编程的"杀手级场景"
在所有的编程任务中,代码重构是从 AI 辅助中获益最大的场景之一。重构有个特点:它需要理解现有代码的逻辑,然后进行"安全的变换"——不改变外部行为,只改善内部结构。这个"理解 → 变换"的过程,AI 做得非常好。
Copilot Chat(以及它的内联聊天模式 Ctrl+I)是进行 AI 辅助重构的最佳入口之一,因为它:
- 直接在编辑器中修改代码(不是在聊天窗口里)
- 以 diff 形式展示修改,方便审查
- 支持多轮迭代(不满意就继续描述,直到满意)
本文聚焦于使用 Copilot Chat 进行各种类型的代码重构——从简单的提取函数到复杂的设计模式改造。
二、重构操作的基础流程
① 选中要重构的代码
② Ctrl+I 打开内联聊天
③ 用自然语言描述你想要的变换
④ Copilot 在编辑器中显示修改后的代码(diff)
⑤ 审查修改 → Ctrl+Enter 接受 / Esc 拒绝
⑥ 如果不满意,继续聊天描述调整
💡 精确描述是关键:不要只说"重构这个"——要说清楚你要达到什么目标。
三、十大常用重构场景
1. 提取函数
选中一大段代码 → Ctrl+I →
"把数据验证逻辑提取到一个独立的 validateUserData 函数中"
2. 简化复杂条件
选中嵌套的 if-else → Ctrl+I →
"用提前返回模式简化这个嵌套条件,把异常情况先处理掉"
3. 循环转函数式
选中 for 循环 → Ctrl+I →
"把这个循环改写为 map/filter/reduce 的链式调用"
4. 回调转 async/await
选中 .then().catch() 链 → Ctrl+I →
"改为 async/await 写法,添加 try-catch 错误处理"
5. 类组件转函数组件
选中 React class 组件 → Ctrl+I →
"把这个 class 组件改写为函数组件 + Hooks"
6. 添加错误处理
选中函数 → Ctrl+I →
"为这个函数添加完整的 try-catch 错误处理和日志记录"
7. 魔法数字转常量
选中函数 → Ctrl+I →
"把函数中的硬编码数字/字符串提取为有意义的常量"
8. 变量重命名(语义化)
选中代码块 → Ctrl+I →
"让所有变量名更有语义:a/b/c 这种单字母变量改为有意义的名称"
9. 拆分大函数
选中 200 行的大函数 → Ctrl+I →
"把这个大函数拆分为 3-5 个职责单一的小函数"
10. 添加类型注解
选中 JavaScript 代码 → Ctrl+I →
"为这段代码添加 TypeScript 类型注解"
四、实战演示:重构一个用户注册控制器
重构前
app.post('/register', async (req, res) => {
// 验证
if (!req.body.email) {
return res.status(400).json({ error: '需要邮箱' });
}
if (!req.body.password || req.body.password.length < 6) {
return res.status(400).json({ error: '密码至少6位' });
}
if (req.body.password !== req.body.confirmPassword) {
return res.status(400).json({ error: '两次密码不一致' });
}
// 检查用户是否存在
const existingUser = await db.query('SELECT * FROM users WHERE email = ?', [req.body.email]);
if (existingUser.length > 0) {
return res.status(409).json({ error: '邮箱已被注册' });
}
// 创建用户
const hashedPassword = await bcrypt.hash(req.body.password, 10);
const result = await db.query(
'INSERT INTO users (email, password, name) VALUES (?, ?, ?)',
[req.body.email, hashedPassword, req.body.name]
);
// 生成 token
const token = jwt.sign(
{ userId: result.insertId, email: req.body.email },
process.env.JWT_SECRET,
{ expiresIn: '7d' }
);
res.status(201).json({ token, userId: result.insertId });
});
重构过程
步骤一:选中验证逻辑,Ctrl+I → “把验证逻辑提取为独立的验证函数,返回所有错误信息而不是遇到第一个就返回”
function validateRegistration(data) {
const errors = {};
if (!data.email) errors.email = '需要邮箱';
if (!data.password || data.password.length < 6) errors.password = '密码至少6位';
if (data.password !== data.confirmPassword) errors.confirmPassword = '两次密码不一致';
return { isValid: Object.keys(errors).length === 0, errors };
}
步骤二:选中整个路由处理函数,Ctrl+I → “用分层架构重构:Controller 只处理请求/响应,业务逻辑放到 Service 中”
// auth.controller.js
app.post('/register', async (req, res) => {
try {
const result = await authService.register(req.body);
res.status(201).json(result);
} catch (error) {
if (error instanceof ValidationError) {
return res.status(400).json({ errors: error.errors });
}
if (error instanceof ConflictError) {
return res.status(409).json({ error: error.message });
}
res.status(500).json({ error: '服务器内部错误' });
}
});
// auth.service.js
class AuthService {
async register(data) {
const validation = validateRegistration(data);
if (!validation.isValid) {
throw new ValidationError(validation.errors);
}
const existingUser = await userRepository.findByEmail(data.email);
if (existingUser) {
throw new ConflictError('邮箱已被注册');
}
const hashedPassword = await bcrypt.hash(data.password, 12);
const user = await userRepository.create({
email: data.email,
password: hashedPassword,
name: data.name,
});
const token = jwt.sign(
{ userId: user.id, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '7d' }
);
return { token, userId: user.id };
}
}
五、重构时的安全策略
⚠️ 重构是"外部行为不变、内部结构改变"的操作。AI 可能不小心改变了外部行为。
安全实践:
- 重构前先 Commit(有 Git 状态可回滚)
- 重构后运行完整测试套件
- 重点关注边界条件(AI 可能在重构中遗漏边缘处理)
- 重构大函数时分步进行(一次只做一种变换)
六、总结
Copilot Chat 让重构从一个"费脑力但必要"的工作变成了一个"描述 → 生成 → 审查"的流畅过程。你需要保留的是判断力——知道什么时候需要重构、重构的目标是什么、AI 的重构是否正确。
下一篇:GitHub Copilot Workspace:从 Issue 到 PR 的 AI 全流程开发体验



