四年前端被问 Code Review90人只看得懂空格和命名

CR 只看格式命名,是初级信号。完整 CR 有 5 层:格式、语法逻辑、异常副作用、架构可维护性、线上性能安全。答到第三层才算合格。

一个问题就能分层

上周面了个 4 年前端。简历写着"熟悉团队代码规范,经常参与 CodeReview"。

我问:你们做 CR 主要看什么?

他脱口而出:格式对不对,命名好不好看。

我追问:如果现在让你做一次完整的 CodeReview,从业务逻辑、边界处理到可维护性、线上风险,你能说出多少个检查维度?不同缺陷的严重优先级怎么区分?

他卡住了。

很多前端以为 Code Review 就是改空格和变量命名。到 2026 年,代码规范和 CR 早不只是格式化代码,这是工程能力的分水岭。

我一般用 5 个层面测人。第三层算合格,第四第五层是高级开发和普通开发的差距。

五层全景

先把全景摆出来,后面逐层拆。

flowchart TD A[提交 PR 进入评审] --> B[L1 基础格式规范] B --> C[L2 语法与业务逻辑] C --> D[L3 业务与异常处理] D --> E[L4 架构与可维护性] E --> F[L5 线上性能与安全] F --> G{缺陷分级} G -->|P0 阻断| H[打回修改] G -->|P1 P2 记录 issue| I[有条件合并] G -->|P3 建议| I

L1 格式规范:别把工具活当技术活

命名、缩进、分号、引号统一、禁止未定义变量------最没技术含量,也最容易被误当成 CR 的全部。

真正的追问在后面:同样是 ESLint 报错,哪些必须阻断合并,哪些只做警告提示?自动 Fix 过后,会不会隐藏真正的 bug?

看配置就明白:

js 复制代码
// .eslintrc.cjs ------ 区分"阻断"和"提示"
module.exports = {
  rules: {
    'no-unused-vars': 'error',   // 阻断:可能是有副作用的导入被误删
    'no-undef': 'error',         // 阻断:运行时必炸
    quotes: ['warn', 'single'],  // 提示:Prettier 的事,不该占用人注意力
    semi: ['warn', 'always'],
    'max-len': 'off',            // 直接关掉,交给格式化工具
  },
};

自动 Fix 最典型的坑:import './polyfill' 被判定为未使用变量删掉,构建产物在低版本浏览器直接白屏。格式问题交给工具,人的注意力留给工具看不见的东西。

L2 语法与业务逻辑:三年经验也常踩空

这一层考代码本身的正确性,检查点密集:

  • 类型是否完备,有没有漏掉边界判断
  • 参数校验:入参为空、undefined、null 场景是否都兜住
  • 重复代码识别:复制粘贴出来的业务逻辑,该不该抽公共工具函数
  • 副作用问题:函数是否纯函数,有没有随意修改入参对象
  • 魔法数字与常量:if (status === 3) 这种散落各处的硬编码

入参修改是最常见的翻车点:

ts 复制代码
// bad:改了入参对象,调用方数据被污染,还漏了兜底
function normalizeUser(user: User) {
  user.name = user.name.trim();
  if (user.age > 18) user.adult = true;
  return user;
}

// good:不改入参,返回新对象,边界先兜住
function normalizeUser(input: UserInput): User {
  const name = input?.name?.trim() ?? '';
  const age = Number.isFinite(input?.age) ? input.age : 0;
  return { ...input, name, age, adult: age >= 18 };
}

注释也得有判断力。必须写的是"为什么这么做"(踩过的坑、绕开的兼容性),不是"做了什么"。// 把 count 加一 这种复述代码的注释,删掉比留着强;注释掉的死代码更是直接删。

L3 异常与副作用:这里才见真功夫

到这一层,评审的是"这段代码上线会不会出事"。

接口请求有没有补异常,失败之后页面如何降级?权限埋点逻辑会不会漏写多写?if-else 嵌套超过四层、条件分支漏了 default,都是典型漏网之鱼。

状态更新风险。组件状态修改造成死循环渲染,是前端特有的一类 bug:

flowchart TD A[组件 render] --> B[useEffect 执行] B --> C[setState 更新状态] C --> D[状态变化触发重渲染] D --> A D -.->|依赖数组缺少该项| E[无限循环 页面卡死]

副作用清理同理------定时器、事件监听、请求,组件销毁时统统要释放,否则就是内存泄漏。

tsx 复制代码
// bad:请求失败无兜底,定时器不清理,卸载后照样 setState
useEffect(() => {
  fetch('/api/list').then(r => r.json()).then(setList);
  const timer = setInterval(poll, 3000);
}, []);

// good:中断 + 存活标记 + 清理函数
useEffect(() => {
  const ac = new AbortController();
  let alive = true;
  fetch('/api/list', { signal: ac.signal })
    .then(r => { if (!r.ok) throw new Error(`HTTP $${r.status}`); return r.json(); })
    .then(d => { if (alive) setList(d); })
    .catch(e => { if (alive) setError(e.message); });
  const timer = setInterval(poll, 3000);
  return () => { alive = false; ac.abort(); clearInterval(timer); };
}, []);

能在这个层面拦下问题的评审者,价值远超"改格式"。

L4 架构与可维护性:高级开发的分水岭

  • 模块职责划分:单个文件、单个函数是不是职责过重
  • 依赖引入:有没有引入冗余包,有没有循环依赖
  • 组件设计:传参是否合理,Props 有没有做约束,是否存在过度封装
  • 复用逻辑:hooks 和工具函数设计得够不够通用,有没有写一堆一次性临时逻辑
  • 兼容性:新 API 有没有降级方案,目标浏览器环境评估过没有

Props 裸奔是最典型的:

tsx 复制代码
// bad:传错类型运行时才炸
function Chart({ data, type, config }) { /* ... */ }

// good:联合类型把非法值挡在编译期
type ChartProps = {
  data: number[];
  type: 'line' | 'bar';
  config?: Partial<ChartConfig>;
};
function Chart({ data, type, config = {} }: ChartProps) { /* ... */ }

L5 性能与安全:事故防线

最后一层,触及线上事故底线。

大数据列表一次性渲染卡死页面、不必要的重渲染、死循环------性能问题这里过一遍。

XSS 更直接:用户输入直接塞进 innerHTML,等于把站点交给攻击者。

ts 复制代码
// bad:直接渲染用户输入
el.innerHTML = `<div>$${comment}</div>`;

// good:要么用 textContent,要么必须过滤
el.textContent = comment;
// 富文本场景
el.innerHTML = DOMPurify.sanitize(comment, { ALLOWED_TAGS: ['b', 'i', 'a'] });

还有两件常被忽略的事:密钥有没有写死在前端代码里(打包后的 dist 目录一 grep 就出来);上线出问题,这段改动能不能快速回滚------一个 PR 混进五个不相关的功能,revert 就是灾难。

新增逻辑有没有补对应的单元测试用例,也在这层问。这个才叫专业。

缺陷优先级:说不出来就是没判断力

说不出优先级,等于没有判断力。我的分法:

级别 判定标准 处理方式
P0 阻断 XSS、内存泄漏、死循环、密钥硬编码 必须改完再合
P1 严重 逻辑漏洞、异常未处理导致功能不可用 本次迭代内修复
P2 一般 重复代码、职责过重、命名有误导性 记录 issue,可先合
P3 建议 格式、注释风格、个人偏好 交给 ESLint 自动修复

关键不是分级本身,而是你知道哪一类问题一旦漏掉,代价是凌晨三点的线上事故。

写在最后

同样一份 CR,有人只看格式排版,有人能提前拦住线上事故。这就是技术深度。

我反问候选人:你现在觉得 CodeReview 真的就只是改改代码格式吗?

你们做 CodeReview 踩过最坑的问题是什么?是某个被放过去的 useEffect,还是一次让整个模块回滚的误合并?评论区聊聊。

有用的话点个赞。

相关推荐
老徐聊GEO4 分钟前
把“安徽“写进题面之后:多平台AI推荐名单的区域扰动测量(2026)
前端·人工智能·算法·geo优化
moshuying15 分钟前
DeppInfer系列之 - 矩阵、注意力与 GPU:拆解 DeepGEMM 与 FlashMLA
前端·javascript·面试
Rocky Ding*23 分钟前
【三年面试五年模拟】2026-10-20_淘天AI应用研发一面面经全解析
论文阅读·人工智能·深度学习·机器学习·面试·aigc·ai-native
利威尔xu28 分钟前
Go IM 源码实战(2):WebSocket 握手 11 步,少 1 个参数连不上
后端·websocket·微服务·面试·golang
燕落南枝38 分钟前
CSS 分组选择器与链接伪类选择器详解
前端·css
其实防守也摸鱼1 小时前
网络安全法竞赛知识总结与题库
前端·网络·人工智能·安全·web安全·重构·nc
山雀~1 小时前
浏览器兼容方案(Web 项目的三层实践)
前端
Jack N1 小时前
【Strapi 系列之五】前端怎么接?Next.js + Tailwind 拉取 Strapi 数据(含代码)
开发语言·前端·javascript·strapi
__sjfzllv___1 小时前
在职前端Leader学习/转行 AI Agent -DAY85
前端
来一首_We_go1 小时前
React Flow Pro 高级交互实现
前端·react.js