2026 届前端校招冲刺:2 万字高频面试题库(含详解、追问与评分标准)

2026 届前端校招冲刺:2 万字高频面试题库(含详解、追问与评分标准)

写给正在准备前端实习、秋招、春招和社招初级岗位的同学。

如果你已经刷过很多零散面试题,大概率会有一种感觉:每一道题看起来都懂,但真正坐到面试官面前,很难把答案讲成一条清晰的线。前端面试并不是单纯背概念,它更像一次"现场建模":面试官问一个问题,你需要快速判断它考的是基础、原理、工程经验,还是解决问题的思路。

这份题库的目标不是堆满所有知识点,而是帮你建立一套能在面试现场稳定输出的回答框架。每道题都包含四部分:

  • 考察点:面试官真正想确认什么。
  • 建议你在面试里怎么讲
  • 追问方向:常见的二连问、三连问。
  • 评分参考:从 1 分到 4 分,判断自己答到什么层次。

适用人群:2026 届前端应届生、准备实习的在校生、0-2 年前端工程师。

建议用法:第一遍快速过目录,确认薄弱模块;第二遍按模块精读;第三遍把每题答案压缩成 60 秒口述版本;最后一遍拿项目经历串联技术点。


目录

  1. HTML 与 CSS 基础
  2. JavaScript 核心
  3. TypeScript
  4. React
  5. Vue
  6. 浏览器与网络
  7. 工程化与构建
  8. 性能优化
  9. 项目设计与前端架构
  10. 编码题与算法
  11. 移动端与跨端
  12. AI、前沿技术与综合潜力

难度说明

  • 简单:应届生必须答出来。
  • 中等:能区分"背过"和"理解过"。
  • 偏难:主要考原理深度、工程经验和表达能力。

一、HTML 与 CSS 基础

Q1:如何理解语义化 HTML?它在真实项目里有什么价值?【简单】

考察点:HTML 基础、可访问性意识、SEO 和工程可维护性。

参考答案

语义化 HTML 指根据内容含义选择合适标签,而不是只用 div 和 span 搭页面。例如页面头部用 header,导航用 nav,主体内容用 main,文章用 article,侧边内容用 aside,表单项使用 label 关联控件。

它的价值主要有三点:

  1. 结构更清晰,团队维护时能直接从标签看出页面层级。
  2. 对搜索引擎和阅读器更友好,能帮助机器理解页面内容。
  3. 可访问性更好,键盘导航、屏幕阅读器、表单聚焦等体验会更稳定。

面试建议:不要只说"有利于 SEO"。更好的回答是:语义化不是为了让页面看起来不同,而是让页面结构对人、浏览器、搜索引擎和辅助设备都有意义。

追问方向

  • sectionarticlediv 如何选择?
  • labelfor 属性有什么作用?
  • 如何让一个自定义按钮具备可访问性?

评分参考

  • 1 分:知道语义化就是用合适标签。
  • 2 分:能举出常见语义标签。
  • 3 分:能说出 SEO、可访问性、维护性价值。
  • 4 分:能结合表单、键盘操作、阅读器体验说明工程场景。

Q2:标准盒模型和 IE 盒模型有什么区别?为什么项目里常用 border-box?【简单】

考察点:CSS 盒模型、布局尺寸计算、工程习惯。

参考答案

  • 标准盒模型 中,widthheight 只表示内容区域,元素最终宽度还要加上 paddingborder
  • IE 盒模型 中,widthheight 包含内容、内边距和边框。

现代项目常用:

css 复制代码
*,
*::before,
*::after {
  box-sizing: border-box;
}

原因是 border-box 更符合布局直觉。比如一个卡片宽度设置为 300px,再加 padding: 16px 后,最终仍然占据 300px,不会因为 padding 导致布局溢出。组件化开发里,如果每个组件都要额外计算 paddingborder,会增加很多不必要的心智负担。

补充box-sizing 不会影响 margin。外边距始终在盒子外部,仍然会影响元素之间的距离。

追问方向

  • box-sizing 会继承吗?
  • width: 100%padding 为什么会溢出?
  • margin 折叠发生在什么情况下?

评分参考

  • 1 分:知道两种盒模型存在差异。
  • 2 分:能说清 width 是否包含 paddingborder
  • 3 分:能解释为什么全局设置 border-box
  • 4 分:能结合组件布局、溢出问题和 margin 折叠一起分析。

Q3:BFC 是什么?它能解决哪些 CSS 布局问题?【中等】

考察点 :格式化上下文、浮动、margin 折叠、布局隔离。

参考答案

BFC 是 Block Formatting Context,块级格式化上下文。可以把它理解为一个独立的布局区域:内部元素的布局不会轻易影响外部,外部浮动元素也不会侵入它的布局计算。

常见触发方式包括:

  • overflow 不为 visible
  • display: flow-root
  • display: inline-block
  • position: absolute/fixed
  • float 不为 none
  • flex/grid 容器的子项等

实际用途有三个高频场景

  1. 清除浮动,让父元素包住浮动子元素。
  2. 避免相邻块级元素 margin 折叠
  3. 实现左侧浮动、右侧自适应的两栏布局,因为 BFC 区域不会和浮动元素重叠。

更推荐的现代写法是 display: flow-root,它语义明确,表示这个元素创建一个新的块格式化上下文,而不是用 overflow: hidden 顺带触发 BFC。

追问方向

  • 为什么 overflow: hidden 可以清除浮动?
  • display: flow-root 相比 clearfix 有什么优点?
  • BFC 能解决所有 margin 折叠吗?

评分参考

  • 1 分:知道 BFC 是块级格式化上下文。
  • 2 分:能说出几个触发条件。
  • 3 分:能结合清浮动、阻止 margin 折叠说明用途。
  • 4 分:能指出现代方案 flow-root,并理解布局隔离的本质。

Q4:flex: 1 到底是什么简写?和 flex: auto 有什么区别?【简单】

考察点:Flex 布局细节、主轴尺寸分配。

参考答案

flexflex-growflex-shrinkflex-basis 的简写。

通常情况下,flex: 1 会被解析为:

css 复制代码
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%;

含义是:项目可以放大,也可以缩小,初始主轴尺寸按 0 计算,然后根据剩余空间分配。

flex: auto 通常等价于 1 1 auto。它和 flex: 1 最大区别在于 flex-basisauto 会先考虑元素自身内容或设置的宽高,再参与空间分配;0% 则更像从零开始按比例分配。因此多个元素都写 flex: 1 时更容易等分,而 flex: auto 会受内容宽度影响。

一句话总结flex: 1 强调按比例分空间,flex: auto 强调先尊重内容尺寸再弹性伸缩。

追问方向

  • flex-basiswidth 同时存在时谁优先?
  • align-itemsalign-content 的区别是什么?
  • flex 子项为什么有时无法被压缩?

评分参考

  • 1 分:知道 flex 是简写。
  • 2 分:能说出三个属性。
  • 3 分:能区分 flex: 1flex: auto
  • 4 分:能解释内容尺寸、最小宽度、溢出之间的关系。

Q5:CSS 选择器优先级如何计算?为什么不建议滥用 !important?【简单】

考察点:级联规则、样式覆盖、工程维护。

参考答案

CSS 优先级可以粗略按四类权重理解:

  1. 内联样式最高。
  2. ID 选择器高于类、属性和伪类。
  3. 类、属性和伪类高于标签和伪元素。
  4. 通配符和继承样式权重最低。

更准确的说法是按选择器元组比较,而不是简单相加。比如 ID 数量多的一方优先;ID 相同再比较类、属性、伪类数量;最后比较标签和伪元素数量。如果优先级相同,后声明的样式覆盖先声明的样式。

!important 会提升声明优先级,但滥用后会破坏正常级联关系。项目里一旦大量使用,后续样式只能用更强选择器或更多 !important 覆盖,调试成本会很高。

工程上更建议通过合理的 CSS 组织方式解决冲突,例如 CSS Modules、BEM、组件作用域样式、设计系统 token,而不是直接堆优先级。

追问方向

  • :is():where() 的优先级有什么差异?
  • CSS Modules 如何解决样式冲突?
  • scoped CSS 是否能完全避免样式污染?

评分参考

  • 1 分:知道选择器有优先级。
  • 2 分:能比较 ID、类、标签的权重。
  • 3 分:能解释 !important 的维护问题。
  • 4 分:能从工程规范角度给出样式隔离方案。

Q6:如何实现水平垂直居中?不同方案适合什么场景?【简单】

考察点:布局基本功、定位、flex/grid。

参考答案

最常用方案是 Flex

css 复制代码
.parent {
  display: flex;
  align-items: center;
  justify-content: center;
}

如果是单个子元素,也可以用 Grid

css 复制代码
.parent {
  display: grid;
  place-items: center;
}

如果需要兼容较旧布局,绝对定位也常见

css 复制代码
.child {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

面试建议 :要说清场景。Flex 适合容器内部整体对齐,Grid 写法简洁,绝对定位适合弹窗、浮层、未知尺寸元素。如果元素宽高固定,还可以用负 margin,但现在不推荐作为首选。

追问方向

  • transform 会不会影响层叠上下文?
  • margin: auto 在 flex 中为什么能居中?
  • 多行文本如何垂直居中?

评分参考

  • 1 分:能写出一种居中方案。
  • 2 分:能写出 Flex 或绝对定位方案。
  • 3 分:能比较多个方案适用场景。
  • 4 分:能结合弹窗、浮层、响应式布局说明取舍。

二、JavaScript 核心

Q7:var、let、const 有什么区别?什么是暂时性死区?【简单】

考察点:作用域、变量提升、ES6 基础。

参考答案

  • var:函数作用域,会变量提升,可以重复声明。
  • letconst :块级作用域,不允许在同一作用域重复声明,并且存在暂时性死区
  • const :声明后不能重新赋值,但如果值是对象,对象内部属性仍然可以修改,因为 const 约束的是绑定关系,不是深层不可变。

暂时性死区 指从块级作用域开始到变量声明语句执行之前,这段区域内不能访问该变量。虽然变量在语义上已经存在于作用域中,但还没有完成初始化,访问会抛出 ReferenceError

实践原则 :默认使用 const,需要重新赋值时用 let,尽量避免 var,这样能减少作用域和提升带来的隐藏问题。

追问方向

  • const obj = {} 后能否修改 obj.a
  • 为什么 typeof x 有时也会报错?
  • for 循环中用 varlet 绑定事件有什么区别?

评分参考

  • 1 分:知道三者基本区别。
  • 2 分:能说出块级作用域和变量提升。
  • 3 分:能解释暂时性死区。
  • 4 分:能结合闭包、循环、工程规范说明使用原则。

Q8:JavaScript 的原型链是什么?new 的过程发生了什么?【中等】

考察点:对象模型、继承机制、构造函数。

参考答案

JavaScript 中每个对象都有一个内部原型,可以通过原型链向上查找属性。当访问对象属性时,如果对象自身没有,就会沿着原型继续查找,直到 null 为止。

  • 函数有 prototype 属性,用来作为通过该函数构造出的实例对象的原型。
  • 实例对象可以通过 __proto__Object.getPrototypeOf 找到自己的原型。

new 大致做了四件事

  1. 创建一个新对象。
  2. 将新对象的原型指向构造函数的 prototype
  3. 以新对象作为 this 执行构造函数。
  4. 如果构造函数返回对象,则返回该对象;否则返回新创建的对象。

追问方向

  • Function.prototypeObject.prototype 的关系是什么?
  • 箭头函数能不能被 new
  • 如何手写一个 new

评分参考

  • 1 分:知道属性会沿原型链查找。
  • 2 分:能解释 prototype 和实例原型关系。
  • 3 分:能完整说明 new 的四步。
  • 4 分:能手写 new 并解释构造函数返回值规则。

Q9:闭包是什么?它有哪些典型应用和风险?【中等】

考察点:词法作用域、函数生命周期、内存意识。

参考答案

闭包是指函数能够访问其词法作用域中的变量,即使外层函数已经执行结束。它的本质不是"函数套函数"这么简单,而是内部函数持有了对外部作用域变量的引用。

典型应用包括:

  • 封装私有变量
  • 函数柯里化
  • 缓存中间结果
  • 防抖节流
  • 模块化封装
  • 事件回调保留状态

闭包的风险主要是变量生命周期被延长。如果闭包持有大量对象、DOM 节点或定时器引用,又没有及时释放,就可能导致内存无法回收。实际项目里要注意在组件卸载时解绑事件、清除定时器、断开无用引用。

好的回答要同时讲清优点和边界:闭包让状态可以被安全保留,但不应该被当成随意存储全局状态的工具。

追问方向

  • 循环里创建闭包为什么容易出错?
  • 闭包一定会造成内存泄漏吗?
  • React Hooks 和闭包有什么关系?

评分参考

  • 1 分:知道闭包能访问外层变量。
  • 2 分:能举出一两个应用。
  • 3 分:能解释变量生命周期延长。
  • 4 分:能结合事件、组件卸载、Hooks stale closure 分析。

Q10:事件循环是什么?宏任务和微任务的执行顺序是怎样的?【中等】

考察点:异步模型、Promise、任务调度。

参考答案

JavaScript 主线程一次只能执行一个任务。事件循环负责协调同步代码、异步回调、渲染和任务队列。

一般执行顺序

  1. 先执行当前调用栈中的同步代码
  2. 同步代码执行完后,清空微任务队列
  3. 然后浏览器可能进行渲染。
  4. 再取出下一个宏任务执行。
  • 常见宏任务setTimeoutsetInterval、DOM 事件回调、网络回调等。
  • 常见微任务Promise.then/catch/finallyqueueMicrotaskMutationObserver

示例

javascript 复制代码
console.log(1);
setTimeout(() => console.log(2));
Promise.resolve().then(() => console.log(3));
console.log(4);

输出是 1 4 3 2。因为同步代码先执行,Promise 回调作为微任务优先于定时器宏任务。

追问方向

  • async/awaitPromise 的执行顺序如何理解?
  • Node.js 事件循环和浏览器有什么不同?
  • 微任务过多会造成什么问题?

评分参考

  • 1 分:知道同步先于异步。
  • 2 分:能区分宏任务和微任务。
  • 3 分:能判断常见输出顺序。
  • 4 分:能联系渲染时机、微任务饥饿、Node 环境差异。

Q11:this 的绑定规则有哪些?箭头函数的 this 有什么特殊之处?【中等】

考察点:调用方式、上下文绑定、函数语义。

参考答案

this 的值不是由函数定义位置单独决定的,而是由调用方式决定。常见规则包括:

  1. 默认调用 时,非严格模式指向全局对象,严格模式为 undefined
  2. 作为对象方法调用时指向调用者。
  3. 通过 callapplybind 显式绑定
  4. 通过 new 调用时指向新创建的实例。

箭头函数 没有自己的 this,它会捕获定义时外层词法作用域中的 this。因此箭头函数适合写回调,避免手动保存 const self = this,但不适合用作对象原型方法、构造函数或需要动态绑定 this 的场景。

优先级new 绑定通常高于显式绑定,显式绑定高于隐式绑定,隐式绑定高于默认绑定。但箭头函数不参与这些规则,因为它的 this 已经由词法环境决定。

追问方向

  • bind 返回的函数还能被 call 改变 this 吗?
  • 箭头函数能不能作为构造函数?
  • DOM 事件回调中普通函数和箭头函数的 this 差异是什么?

评分参考

  • 1 分:知道 this 和调用方式有关。
  • 2 分:能说出默认、隐式、显式、new 绑定。
  • 3 分:能解释箭头函数词法 this
  • 4 分:能分析优先级和真实代码输出。

Q12:如何理解 Promise?then 链式调用为什么可以连续执行?【中等】

考察点:异步抽象、状态机、链式调用。

参考答案

Promise 是对异步结果的封装,它有三种状态:pendingfulfilledrejected。状态只能从 pending 变成 fulfilledrejected,且一旦改变就不可逆。

then 之所以能链式调用,是因为它会返回一个新的 Promise。回调函数的返回值会决定新 Promise 的状态:

  • 如果返回普通值,新 Promise 变为 fulfilled
  • 如果抛出错误,新 Promise 变为 rejected
  • 如果返回另一个 Promise,新 Promise 会跟随它的最终状态。

这也是为什么可以写:

javascript 复制代码
fetchUser()
  .then(user => fetchOrders(user.id))
  .then(orders => render(orders))
  .catch(error => report(error));

catch 本质上也是 then(null, onRejected) 的语法糖。finally 不接收成功值或失败原因用于改变主流程,常用于关闭 loading、释放资源等收尾逻辑。

追问方向

  • Promise 状态为什么不可逆?
  • Promise.allPromise.allSettled 的区别?
  • 如何限制并发请求数量?

评分参考

  • 1 分:知道 Promise 处理异步。
  • 2 分:能说出三种状态。
  • 3 分:能解释 then 返回新 Promise
  • 4 分:能分析错误传播、并发控制和状态吸收。

Q13:深拷贝和浅拷贝有什么区别?如何实现一个可靠的深拷贝?【中等】

考察点:引用类型、对象复制、边界情况。

参考答案

浅拷贝 只复制对象第一层属性。如果属性值是引用类型,新对象和旧对象仍然共享同一个引用。常见浅拷贝方式包括扩展运算符、Object.assign、数组的 slice 等。

深拷贝 会递归复制嵌套对象,使新旧对象在结构上独立。JSON.parse(JSON.stringify(obj)) 是最常见但不可靠的方案,它无法处理 undefined、函数、SymbolDateRegExpMapSet、循环引用等情况。

现代浏览器和 Node 环境可以考虑 structuredClone,它支持更多内置类型,也能处理循环引用,但不能克隆函数和 DOM 节点。

如果手写深拷贝,需要处理基本类型、数组、普通对象、日期、正则、Map、Set,并用 WeakMap 记录已拷贝对象,避免循环引用导致递归爆栈。

追问方向

  • structuredClone 有哪些限制?
  • 为什么循环引用会导致栈溢出?
  • Immer 是如何避免大规模深拷贝成本的?

评分参考

  • 1 分:知道浅拷贝共享引用。
  • 2 分:能说出 JSON 深拷贝的问题。
  • 3 分:能提到 structuredCloneWeakMap
  • 4 分:能从性能和不可变数据结构角度分析。

Q14:防抖和节流有什么区别?分别适合什么业务场景?【简单】

考察点:高频事件优化、定时器、用户体验。

参考答案

  • 防抖 是指事件频繁触发时,只在最后一次触发后等待一段时间再执行。如果等待期间又触发,就重新计时。适合搜索输入联想、窗口尺寸变化后重新计算布局、表单校验等场景。
  • 节流 是指事件频繁触发时,固定时间间隔内最多执行一次。适合滚动加载、拖拽移动、按钮连点保护、页面滚动位置上报等场景。

一句话区分:防抖关注"最后一次",节流关注"固定频率"。如果用户持续输入搜索词,用防抖可以避免每个字符都发请求;如果用户持续滚动页面,用节流可以保证逻辑按稳定频率执行。

追问方向

  • 防抖如何支持立即执行?
  • 节流用时间戳和定时器实现有什么区别?
  • React 中如何避免每次渲染都重新创建防抖函数?

评分参考

  • 1 分:知道二者用于限制高频执行。
  • 2 分:能区分最后一次和固定频率。
  • 3 分:能结合业务场景说明选择。
  • 4 分:能写出实现并处理立即执行、取消、闭包问题。

三、TypeScript

Q15:TypeScript 相比 JavaScript 解决了什么问题?【简单】

考察点:类型系统价值、工程化意识。

参考答案

TypeScript 是 JavaScript 的超集,它主要通过静态类型系统提升大型项目的可维护性。它不能让运行时错误完全消失,但能把很多低级错误提前到开发阶段暴露出来。

它解决的问题包括:

  • 接口字段不明确
  • 函数入参和返回值不清晰
  • 重构风险高
  • 多人协作时依赖口头约定
  • IDE 智能提示弱

对于中大型前端项目,类型本身也是一种文档,能帮助开发者快速理解模块边界。

注意:TypeScript 的类型只存在于编译阶段,最终运行的仍然是 JavaScript。因此接口返回数据仍然需要运行时校验,不能因为写了类型就默认后端数据一定可靠。

追问方向

  • TypeScript 能否保证运行时类型安全?
  • anyunknownnever 的区别?
  • 类型声明文件 .d.ts 的作用是什么?

评分参考

  • 1 分:知道 TS 增加类型。
  • 2 分:能说出类型检查和提示价值。
  • 3 分:能结合重构、协作、接口约束说明。
  • 4 分:能指出编译期类型和运行时数据之间的边界。

Q16:interface 和 type 有什么区别?如何选择?【中等】

考察点:类型建模、声明合并、扩展能力。

参考答案

  • interface 主要用于描述对象结构,可以通过 extends 扩展,并支持声明合并 。多个同名 interface 会自动合并,这在扩展第三方库类型时很有用。
  • type 可以给任意类型起别名,不仅能描述对象,还能描述联合类型、交叉类型、元组、条件类型、映射类型等。它表达能力更强,但不支持同名声明合并。

选择原则 :描述公开对象结构或类实现约束时优先用 interface;需要联合、交叉、工具类型组合时用 type。团队内部更重要的是风格统一。

追问方向

  • 什么是声明合并?
  • interface A extends Btype A = B & C 有什么差异?
  • 如何给第三方库补充类型?

评分参考

  • 1 分:知道二者都能描述对象。
  • 2 分:能说出 type 支持联合类型。
  • 3 分:能说出 interface 声明合并。
  • 4 分:能结合库类型扩展和团队规范说明选择。

Q17:any 和 unknown 有什么区别?为什么更推荐 unknown?【简单】

考察点:类型安全、边界处理。

参考答案

  • any 会绕过类型检查,相当于告诉 TypeScript"不要管这个变量"。一旦使用 any,后续属性访问、函数调用、赋值都不会被检查,类型系统的保护会被削弱。
  • unknown 表示"我现在不知道它是什么类型"。它可以接收任何值,但使用之前必须做类型缩小 ,例如 typeofArray.isArray、自定义类型守卫等。

因此在处理外部输入时,比如接口响应、JSON.parse、第三方 SDK 回调,更推荐先用 unknown 表达不确定,再通过校验收窄成可信类型。这样既承认数据来源不可靠,又能保留类型检查。

追问方向

  • never 表示什么?
  • 如何写自定义类型守卫?
  • JSON.parse 的返回值该如何建模?

评分参考

  • 1 分:知道 any 放弃检查。
  • 2 分:知道 unknown 使用前要收窄。
  • 3 分:能写出类型收窄例子。
  • 4 分:能结合接口数据、错误处理、运行时校验说明。

Q18:泛型是什么?它解决了什么问题?【中等】

考察点:类型复用、约束、推导。

参考答案

泛型可以把类型作为参数传入,让函数、接口、类在保持类型安全的同时具备复用能力。它解决的是"逻辑相同但类型不同"的问题。

例如:

typescript 复制代码
function identity<T>(value: T): T {
  return value;
}

这里 T 会根据传入值自动推导。传入字符串返回字符串,传入数字返回数字,既不需要写多个函数,也不会丢失类型信息。

泛型还可以通过 extends 加约束:

typescript 复制代码
function getLength<T extends { length: number }>(value: T) {
  return value.length;
}

这表示传入的类型必须有 length 属性。

面试要点:泛型不是为了写复杂类型,而是为了在抽象和类型安全之间取得平衡。

追问方向

  • 泛型默认类型怎么写?
  • keyof 和泛型如何配合?
  • 如何实现一个类型安全的 getProperty

评分参考

  • 1 分:知道泛型是类型参数。
  • 2 分:能写出简单泛型函数。
  • 3 分:能使用泛型约束。
  • 4 分:能结合 keyof、条件类型、工具类型完成类型建模。

Q19:TypeScript 常见工具类型有哪些?它们底层思路是什么?【中等】

考察点:映射类型、条件类型、类型变换。

参考答案

常见工具类型包括 Partial<T>Required<T>Readonly<T>Pick<T, K>Omit<T, K>Record<K, T>ReturnType<T>Parameters<T> 等。

它们的底层思路主要是映射类型索引访问类型条件类型infer

例如 Partial<T> 会遍历对象类型的所有 key,并把每个属性变成可选:

typescript 复制代码
type MyPartial<T> = {
  [K in keyof T]?: T[K];
};

Pick<T, K> 是从对象中选择一部分 key,Omit<T, K> 可以理解为先排除 key 再 PickReturnType 则通过条件类型和 infer 推断函数返回值。

面试建议:不用死背所有实现,但要能说明工具类型是在类型层面对对象结构做转换,提高类型复用能力。

追问方向

  • 如何手写 PickOmitReturnType
  • Record<string, unknown> 和普通对象类型有什么区别?
  • 深层 Partial 如何实现?

评分参考

  • 1 分:能说出几个工具类型名称。
  • 2 分:知道它们用于类型变换。
  • 3 分:能手写 PartialPick
  • 4 分:能理解映射类型、条件类型和 infer 的组合。

四、React

Q20:React 的核心思想是什么?为什么说 UI 是状态的函数?【简单】

考察点:声明式 UI、组件化、状态驱动。

参考答案

React 的核心思想可以概括为:组件化、声明式、状态驱动。开发者不需要直接命令 DOM 一步步怎么变,而是描述某个状态下 UI 应该长什么样。状态变化后,React 负责计算新旧 UI 的差异并更新视图。

"UI 是状态的函数"可以理解为:

复制代码
UI = f(state)

同样的状态应该渲染出同样的界面。当状态变化时,组件重新渲染,得到新的 UI 描述。这种模型让复杂界面更容易推理,因为你关注的是状态和视图之间的映射关系,而不是手动维护 DOM 的每一步变化。

实践要求 :尽量减少派生状态和重复状态。例如列表长度可以从数组计算出来,就不应该再单独维护一个 count,否则容易出现数据不一致。

追问方向

  • 受控组件和非受控组件的区别?
  • 为什么不要直接修改 state
  • React 重新渲染是否等于真实 DOM 一定更新?

评分参考

  • 1 分:知道 React 是组件化框架。
  • 2 分:能说出声明式和状态驱动。
  • 3 分:能解释 UI 与 state 的关系。
  • 4 分:能结合派生状态、不可变更新、渲染优化说明实践。

Q21:React Fiber 是什么?它解决了什么问题?【偏难】

考察点:React 渲染架构、调度、可中断渲染。

参考答案

Fiber 是 React 的一种内部数据结构和协调架构。早期 React 更新过程接近递归同步执行,一旦组件树很大,主线程会长时间被占用,导致页面卡顿、输入不响应。

Fiber 把渲染工作拆分成一个个可执行单元,每个组件对应一个 Fiber 节点。这样 React 可以在浏览器有空闲时间时分片执行渲染任务,并根据优先级决定哪些更新更紧急。比如用户输入优先级高,普通列表渲染优先级低。

Fiber 架构让 React 具备了可中断、可恢复、可优先级调度的能力,是并发特性的基础。

注意 :Fiber 主要影响 render 阶段;commit 阶段涉及真实 DOM 变更,需要保持同步执行,避免界面处于不一致状态。

追问方向

  • render 阶段和 commit 阶段有什么区别?
  • 为什么 commit 阶段不能随意中断?
  • React 18 并发渲染解决了什么体验问题?

评分参考

  • 1 分:知道 Fiber 是 React 内部机制。
  • 2 分:能说出它把任务拆成小单元。
  • 3 分:能解释可中断和优先级调度。
  • 4 分:能区分 render/commit,并联系并发渲染。

Q22:useEffect 和 useLayoutEffect 有什么区别?【中等】

考察点:副作用时机、渲染流程、闪烁问题。

参考答案

  • useEffect:在浏览器完成绘制之后异步执行,不会阻塞页面显示,适合请求数据、订阅事件、记录日志、操作非布局相关副作用。
  • useLayoutEffect:在 DOM 更新之后、浏览器绘制之前同步执行,会阻塞绘制。它适合读取布局并同步修改 DOM 的场景,比如测量元素尺寸后立即调整位置,避免用户看到闪烁。

选择原则

  • 默认使用 useEffect
  • 只有当副作用必须在绘制前完成,否则会出现明显视觉跳动时,才使用 useLayoutEffect。滥用 useLayoutEffect 会延长页面阻塞时间,影响性能。

共同点:两者都可以返回清理函数,用于解绑事件、取消订阅、清除定时器。依赖数组要准确,否则容易出现重复执行或闭包读取旧值的问题。

追问方向

  • 依赖数组为空表示什么?
  • 如何处理 effect 中的异步请求竞态?
  • 为什么服务端渲染中 useLayoutEffect 会有警告?

评分参考

  • 1 分:知道二者都是处理副作用。
  • 2 分:能说出执行时机不同。
  • 3 分:能解释绘制前后和闪烁问题。
  • 4 分:能结合清理函数、竞态、SSR 场景分析。

Q23:React Hooks 为什么不能写在条件语句里?【中等】

考察点:Hooks 调用顺序、状态保存机制。

参考答案

Hooks 依赖稳定的调用顺序 来关联每次渲染中的状态。React 并不是通过变量名识别某个 useState,而是按照 Hooks 调用顺序依次保存和读取状态。

如果把 Hook 写在条件语句、循环或嵌套函数中,某次渲染调用了,下一次渲染没调用,后续 Hooks 的顺序就会错位,React 可能把 A 状态读成 B 状态,导致不可预测问题。

因此 Hooks 有两条基本规则:

  1. 只能在函数组件或自定义 Hook 顶层调用
  2. 不能在条件、循环、普通函数里调用。

如果确实有条件逻辑,应把条件写到 Hook 内部:

javascript 复制代码
useEffect(() => {
  if (!enabled) return;
  subscribe();
  return unsubscribe;
}, [enabled]);

追问方向

  • 自定义 Hook 本质是什么?
  • Hooks 如何保存多个 state
  • 为什么 ESLint 能检查 Hooks 规则?

评分参考

  • 1 分:知道不能在条件里写 Hook。
  • 2 分:能说出调用顺序必须稳定。
  • 3 分:能解释状态错位问题。
  • 4 分:能结合自定义 Hook 和 lint 规则说明机制。

Q24:useMemo 和 useCallback 的区别是什么?什么时候不该用?【中等】

考察点:渲染优化、引用稳定、过度优化。

参考答案

  • useMemo:用于缓存计算结果。
  • useCallback:用于缓存函数引用。

可以粗略理解为:

javascript 复制代码
useCallback(fn, deps) 
// 类似于 
useMemo(() => fn, deps)

它们常见用途有两个:

  1. 避免昂贵计算在每次渲染时重复执行。
  2. 保持对象或函数引用稳定,配合 React.memo 避免子组件无意义重渲染。

但它们不是越多越好 。每次使用都需要维护依赖数组,也会增加代码复杂度。对于普通计算、很轻量的组件、没有传给 memo 子组件的函数,使用它们可能收益很低,甚至让代码更难维护。

工程判断 :先确认性能问题,再用 profiler 或实际场景定位,而不是凭感觉给所有函数包 useCallback

追问方向

  • React.memo 是什么?
  • 依赖数组写错会有什么问题?
  • 为什么对象字面量会导致子组件重新渲染?

评分参考

  • 1 分:知道二者用于缓存。
  • 2 分:能区分缓存值和缓存函数。
  • 3 分:能说明与 React.memo 的配合。
  • 4 分:能讲清过度优化成本和定位方法。

Q25:React 中状态管理如何选型?Context、Redux、Zustand 分别适合什么场景?【中等】

考察点:状态分层、工程选型、复杂度控制。

参考答案

状态管理先要区分状态类型:

  • 组件局部状态
  • 跨组件共享状态
  • 服务端缓存状态
  • URL 状态
  • 表单状态

不同状态不一定要放到同一个全局仓库。

  • Context:适合低频更新的全局配置,比如主题、语言、登录用户信息。它不是完整状态管理库,更新时可能导致消费该 Context 的组件重新渲染,需要谨慎拆分。
  • Redux:适合状态流复杂、需要严格可预测、需要中间件、调试工具和团队规范的大型项目。它样板代码较多,但约束强。
  • Zustand:更轻量,API 简洁,适合中小型项目或局部复杂状态。

服务端数据缓存 通常更推荐 React QuerySWR 这类工具,因为它们处理缓存、重试、失效、加载状态等问题更专业。

追问方向

  • Context 为什么可能导致性能问题?
  • Redux Toolkit 解决了 Redux 哪些痛点?
  • 服务端状态和客户端状态有什么区别?

评分参考

  • 1 分:知道几种状态管理方案。
  • 2 分:能说出基本使用场景。
  • 3 分:能区分客户端状态和服务端缓存。
  • 4 分:能从团队规模、调试、性能、复杂度角度选型。

Q26:React 组件 key 的作用是什么?为什么不建议用数组下标作为 key?【简单】

考察点:列表 diff、组件身份、渲染正确性。

参考答案

key 用来帮助 React 在列表更新时识别每个元素的稳定身份 。React diff 时会根据 key 判断哪些元素是新增、删除、移动或复用。

不建议用数组下标作为 key,是因为当列表发生插入、删除、排序时,下标会变化。React 可能错误复用组件实例,导致输入框内容错位、动画异常、组件内部状态跟着错误项移动。

安全情况 :只有在列表完全静态、不排序、不插入删除时,下标 key 才相对安全。实际项目中更推荐使用数据本身的唯一 ID。

追问方向

  • key 是否会作为 props 传给组件?
  • 为什么随机数 key 也不好?
  • React diff 为什么不做完整树编辑距离比较?

评分参考

  • 1 分:知道 key 用于列表。
  • 2 分:能说出帮助 React 识别元素。
  • 3 分:能解释下标 key 的错位问题。
  • 4 分:能联系组件状态复用和 diff 性能。

五、Vue

Q27:Vue 2 和 Vue 3 响应式原理有什么区别?【中等】

考察点 :响应式系统、Object.definePropertyProxy

参考答案

  • Vue 2 :主要基于 Object.defineProperty 对对象属性做 getter/setter 劫持。在读取属性时收集依赖,在修改属性时通知依赖更新。它的问题是无法直接监听新增属性和删除属性,数组的一些变更也需要特殊处理。
  • Vue 3 :使用 Proxy 代理整个对象,可以拦截读取、设置、删除、in、遍历等操作,对新增属性、删除属性、数组索引变化支持更自然。配合 Reflect 可以更规范地执行默认行为。

Vue 3 的响应式系统也更独立,可以通过 reactiverefcomputedwatch 等 API 在组件外使用。这让组合式 API 更适合逻辑复用。

追问方向

  • refreactive 如何选择?
  • 为什么解构 reactive 对象会丢失响应式?
  • toRefs 的作用是什么?

评分参考

  • 1 分:知道 Vue 2 和 Vue 3 响应式实现不同。
  • 2 分:能说出 definePropertyProxy
  • 3 分:能说明 Vue 2 的新增属性限制。
  • 4 分:能结合 Composition API、解构丢失响应式分析。

Q28:computed 和 watch 有什么区别?【简单】

考察点:派生状态、副作用、缓存。

参考答案

  • computed :用于根据已有响应式数据计算派生值,具有缓存能力。只要依赖不变,多次访问不会重复计算。它适合模板展示、格式化、过滤列表、拼接字段等场景。
  • watch :用于监听响应式数据变化并执行副作用,例如发请求、写本地存储、手动操作 DOM、上报日志等。它关注的是"变化发生后要做什么"。

选择原则

  • 能用计算结果表达的,用 computed
  • 需要执行异步或副作用的,用 watch
  • 不要用 watch 去维护一个本可以由 computed 得出的状态,否则容易造成重复状态和同步问题。

追问方向

  • computed 为什么有缓存?
  • watchwatchEffect 的区别?
  • watch 如何处理异步竞态?

评分参考

  • 1 分:知道 computed 计算值,watch 监听变化。
  • 2 分:能说出 computed 有缓存。
  • 3 分:能结合副作用场景选择。
  • 4 分:能指出避免重复派生状态的设计原则。

Q29:Vue 的 nextTick 是什么?为什么修改数据后不能立即拿到最新 DOM?【中等】

考察点:异步更新队列、DOM 渲染时机。

参考答案

Vue 修改响应式数据后,并不会同步立刻更新 DOM,而是把更新任务放入队列,在当前同步代码执行完后批量刷新。这样可以合并多次数据变化,避免频繁操作 DOM。

nextTick 用于在下一次 DOM 更新完成后执行回调 。如果你修改数据后立刻读取 DOM,读到的可能还是旧 DOM;把读取逻辑放到 nextTick 中,就能拿到更新后的结果。

例如弹窗打开后需要聚焦输入框、列表渲染后需要滚动到底部、数据变化后测量元素高度,这些都适合使用 nextTick

追问方向

  • Vue 为什么要批量异步更新?
  • nextTick 底层可能用哪些异步 API?
  • React 中有没有类似概念?

评分参考

  • 1 分:知道 nextTick 和 DOM 更新有关。
  • 2 分:能说出 Vue DOM 异步更新。
  • 3 分:能举出读取 DOM 的业务场景。
  • 4 分:能联系批处理、微任务、性能优化说明。

Q30:Vue 组件通信有哪些方式?如何选择?【简单】

考察点:组件设计、数据流、状态管理。

参考答案

  • 父子组件通信 :最常用的是 propsemit。父组件通过 props 传数据,子组件通过 emit 通知父组件事件,符合单向数据流。
  • 跨层级通信 :可以使用 provide/inject,适合主题、表单上下文、组件库内部上下文等场景。
  • 兄弟组件通信:可以提升状态到共同父组件,也可以使用全局状态管理,如 Pinia。

避免滥用事件总线:事件总线短期方便,但数据来源不清晰,调试困难。Pinia 更适合管理跨页面、跨模块共享状态;而服务端缓存数据仍然可以交给专门的数据请求库或封装层处理。

追问方向

  • props 为什么不建议子组件直接修改?
  • provide/inject 是否响应式?
  • Pinia 相比 Vuex 有什么变化?

评分参考

  • 1 分:能说出 propsemit
  • 2 分:能说出 provide/inject 或 Pinia。
  • 3 分:能按组件关系选择方案。
  • 4 分:能从数据流清晰度和可维护性角度分析。

六、浏览器与网络

Q31:从输入 URL 到页面展示,浏览器发生了什么?【偏难】

考察点:网络链路、浏览器渲染、整体知识面。

参考答案

可以按几个阶段回答:

  1. 浏览器解析 URL,检查缓存、HSTS、协议等信息。
  2. 进行 DNS 解析,把域名解析成 IP。
  3. 建立连接,HTTPS 还需要 TLS 握手。
  4. 浏览器发送 HTTP 请求,服务器处理后返回响应。
  5. 浏览器接收 HTML,开始解析并构建 DOM;遇到 CSS 构建 CSSOM;两者结合生成渲染树。
  6. 进行布局、绘制、合成,最终展示页面。
  7. 加载 JS、图片、字体等资源,并可能触发后续渲染更新。

回答要点:不要讲成死记硬背流水账。要突出关键点:

  • DNS 可能缓存
  • TCP/TLS 有握手成本
  • HTTP 缓存会影响是否真正请求服务器
  • CSS 会影响渲染
  • JS 可能阻塞 HTML 解析
  • 现代浏览器会做预解析和资源优先级调度

追问方向

  • DNS 解析有哪些缓存?
  • CSS 和 JS 分别如何阻塞渲染?
  • HTTP/2 对这个过程有哪些优化?

评分参考

  • 1 分:能说出 DNS、请求、渲染几个阶段。
  • 2 分:能按顺序描述主要流程。
  • 3 分:能解释缓存、TLS、DOM/CSSOM。
  • 4 分:能联系资源优先级、阻塞渲染和性能优化。

Q32:浏览器缓存有哪些类型?强缓存和协商缓存如何工作?【中等】

考察点:HTTP 缓存、性能优化、部署策略。

参考答案

浏览器缓存主要包括 HTTP 缓存、内存缓存、磁盘缓存、Service Worker 缓存等。面试最常问的是 HTTP 强缓存和协商缓存。

  • 强缓存 :浏览器在缓存有效期内直接使用本地资源,不向服务器发送请求。相关响应头主要是 Cache-Control,例如 max-agepublicprivateno-cacheno-storeExpires 是较老的字段,依赖客户端时间。
  • 协商缓存 :缓存过期或需要确认时,浏览器向服务器发送条件请求。常见字段包括 ETag/If-None-MatchLast-Modified/If-Modified-Since。如果资源未变化,服务器返回 304,浏览器继续使用本地缓存。

工程实践:通常对带 hash 的静态资源设置长强缓存,对 HTML 设置不缓存或短缓存,确保发版后入口文件能及时更新。

追问方向

  • no-cacheno-store 的区别?
  • ETagLast-Modified 谁优先?
  • 前端发版后用户白屏可能和缓存有什么关系?

评分参考

  • 1 分:知道缓存能减少请求。
  • 2 分:能区分强缓存和协商缓存。
  • 3 分:能说出关键响应头。
  • 4 分:能结合 hash 静态资源和 HTML 缓存部署策略。

Q33:HTTP 状态码 301、302、304、401、403、500 分别表示什么?【简单】

考察点:HTTP 基础、接口排查能力。

参考答案

  • 301:永久重定向,资源地址长期变更。
  • 302:临时重定向,客户端下次仍可以请求原地址。
  • 304:资源未修改,配合协商缓存使用,响应体通常为空。
  • 401:未认证,通常需要登录或 token 无效。
  • 403:已认证但没有权限。
  • 500:服务器内部错误。

分类归纳:2xx 成功,3xx 重定向或缓存,4xx 客户端问题,5xx 服务端问题。这样比零散背诵更清晰。

实际排查接口时,401 更关注登录态、token、cookie;403 更关注权限、角色、资源归属;500 则要看服务端日志、请求参数和链路追踪。

追问方向

  • 301 和 302 对 SEO、缓存有什么影响?
  • 401 和 403 的根本区别?
  • 502、503、504 常见于什么场景?

评分参考

  • 1 分:能说出几个常见状态码。
  • 2 分:能按 2xx/3xx/4xx/5xx 分类。
  • 3 分:能区分 401 和 403。
  • 4 分:能结合接口排查和缓存机制说明。

Q34:跨域是什么?CORS 的关键响应头有哪些?【中等】

考察点:同源策略、前后端联调、安全边界。

参考答案

跨域源于浏览器同源策略。协议、域名、端口任意一个不同,就属于不同源。浏览器限制脚本读取跨源响应内容,以保护用户数据安全。

CORS 是浏览器支持的跨域资源共享机制。服务端通过响应头声明允许哪些来源访问资源。常见响应头包括:

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers
  • Access-Control-Allow-Credentials

对于复杂请求,浏览器会先发送 OPTIONS 预检请求,确认服务器允许后再发送真实请求。

注意:跨域限制主要发生在浏览器环境。服务器之间请求不受浏览器同源策略限制。开发环境代理能解决本地联调问题,但生产环境仍需要服务端正确配置 CORS 或通过同域网关转发。

追问方向

  • 什么是简单请求和复杂请求?
  • 带 cookie 的跨域请求需要哪些配置?
  • JSONP 为什么能跨域?有什么缺点?

评分参考

  • 1 分:知道跨域和同源策略有关。
  • 2 分:能说出协议、域名、端口。
  • 3 分:能说明 CORS 响应头和预检。
  • 4 分:能结合凭证、代理、生产部署安全分析。

Q35:Cookie、LocalStorage、SessionStorage 有什么区别?【简单】

考察点:浏览器存储、安全、登录态。

参考答案

  • Cookie :会随同域请求自动发送给服务器,容量较小,常用于登录态、会话标识、服务端识别用户。它可以设置过期时间、域、路径、HttpOnlySecureSameSite 等属性。
  • LocalStorage:容量相对更大,默认长期保存,除非主动删除。
  • SessionStorage:只在当前标签页会话内有效,页面关闭后清除,同源但不同标签页通常不共享。

安全建议 :不建议把敏感 token 随意放入 LocalStorage,因为一旦发生 XSS,脚本可以读取。Cookie 如果设置 HttpOnly,前端 JS 无法读取,能降低 XSS 窃取风险,但仍要考虑 CSRF,可通过 SameSite、CSRF Token 等方式防护。

追问方向

  • HttpOnlySecureSameSite 分别做什么?
  • XSS 和 CSRF 有什么区别?
  • IndexedDB 适合什么场景?

评分参考

  • 1 分:知道三者都能存数据。
  • 2 分:能区分生命周期和是否随请求发送。
  • 3 分:能说出 Cookie 安全属性。
  • 4 分:能结合 XSS、CSRF 和登录态设计分析。

七、工程化与构建

Q36:Webpack 和 Vite 的核心区别是什么?【中等】

考察点:构建工具、开发体验、模块机制。

参考答案

  • Webpack:传统打包器,开发时通常会先分析依赖图,把模块打包后再交给浏览器。它生态成熟、插件丰富、适合复杂项目,但冷启动和大项目增量编译可能较慢。
  • Vite:开发环境基于浏览器原生 ES Modules。启动时不需要先把整个项目打包,而是按需编译浏览器请求到的模块。依赖预构建通常使用 esbuild,速度很快。生产构建默认基于 Rollup,产物优化能力强。

一句话总结:Webpack 更像"先打包再运行",Vite 开发模式更像"先启动,按需转换"。但这不代表 Vite 永远优于 Webpack。老项目、复杂 loader/plugin、特殊构建链路、微前端遗留系统,Webpack 仍然常见。

追问方向

  • Vite 为什么冷启动快?
  • 依赖预构建解决了什么问题?
  • 生产环境 Vite 为什么还要打包?

评分参考

  • 1 分:知道二者都是构建工具。
  • 2 分:能说出 Vite 开发环境快。
  • 3 分:能解释 ESM 按需加载和预构建。
  • 4 分:能结合项目复杂度和生态成熟度做选型。

Q37:Babel 是做什么的?和 Polyfill 有什么区别?【中等】

考察点:JS 编译、兼容性、运行时 API。

参考答案

  • Babel :主要负责语法转换,把新版 JavaScript 语法转换成目标环境能理解的旧语法。例如把箭头函数、可选链、类语法等转换成兼容写法。
  • Polyfill :负责补齐运行时缺失的 API 。例如旧浏览器没有 PromiseArray.prototype.includesObject.assign,只靠 Babel 转语法是不够的,需要引入对应 polyfill。

区分方式 :Babel 解决"语法能不能解析",Polyfill 解决"API 存不存在"。实际项目里通常结合 @babel/preset-envbrowserslistcore-js 按目标浏览器自动决定转换和注入策略。

追问方向

  • browserslist 的作用是什么?
  • useBuiltIns: usageentry 有什么区别?
  • Babel 插件和预设的区别?

评分参考

  • 1 分:知道 Babel 转换 JS。
  • 2 分:能区分语法转换和 API 补齐。
  • 3 分:能举出 Promise 需要 polyfill。
  • 4 分:能结合目标浏览器、core-js、按需注入说明。

Q38:Tree Shaking 是什么?为什么有时不生效?【中等】

考察点:打包优化、ESM、模块副作用。

参考答案

Tree Shaking 用于移除未使用代码,减少最终包体积。它依赖静态分析,因此 ES Modules 的 import/export 更适合 Tree Shaking,因为依赖关系在编译阶段就比较明确。

不生效的常见原因

  1. 使用 CommonJS 动态导入导出。
  2. 模块存在副作用,打包器不敢删除。
  3. 引入方式不正确,例如从大包入口整体引入。
  4. 代码被动态访问。
  5. 库没有正确声明 sideEffects

注意:Tree Shaking 删除的是"未被引用且可证明无副作用"的代码,不是简单按文件删除。

追问方向

  • ESM 为什么比 CommonJS 更容易 Tree Shaking?
  • package.jsonsideEffects 是什么?
  • 如何分析打包产物体积?

评分参考

  • 1 分:知道 Tree Shaking 删除无用代码。
  • 2 分:能说出依赖 ESM 静态分析。
  • 3 分:能说明副作用导致不生效。
  • 4 分:能结合组件库按需引入和产物分析排查。

Q39:前端项目为什么需要 ESLint、Prettier、Husky、Commitlint?【简单】

考察点:工程规范、团队协作、质量门禁。

参考答案

  • ESLint:检查代码质量和潜在问题,比如未使用变量、Hooks 规则、危险写法等。
  • Prettier:统一格式,减少团队在缩进、换行、引号上的争论。
  • Husky:接入 Git hooks,在提交前执行检查、测试或格式化。
  • Commitlint:规范提交信息,让提交历史更清晰,也方便后续自动生成 changelog 或做版本发布。

本质:这些工具不是为了"显得专业",而是把团队约定自动化。规则如果只写在文档里,很容易被忘记;放到工具链里,才能稳定执行。

追问方向

  • ESLint 和 Prettier 冲突如何处理?
  • pre-commitpre-push 适合分别做什么?
  • 为什么提交阶段不建议跑过慢任务?

评分参考

  • 1 分:知道这些是规范工具。
  • 2 分:能说出各自基本作用。
  • 3 分:能理解自动化质量门禁价值。
  • 4 分:能从速度、体验、CI 分层角度设计规范流程。

Q40:Monorepo 是什么?适合什么团队和项目?【中等】

考察点:仓库管理、依赖复用、工程规模。

参考答案

Monorepo 指把多个相关项目或包放在同一个仓库中管理。它适合多个应用共享组件库、工具库、类型定义、配置和发布流程的场景。

优点

  • 跨包修改更容易
  • 依赖版本统一
  • 代码复用方便
  • 规范集中管理

缺点

  • 仓库规模变大后,构建、测试、权限、发布流程都需要更强工具支持,否则会变慢、变乱。

常见工具包括 pnpm workspaceTurborepoNxRush 等。一个成熟 Monorepo 需要处理任务编排、缓存、增量构建、依赖拓扑、版本发布和 CI 优化。

选型判断:当多个项目共享大量基础能力,并且团队有能力建设工具链时,Monorepo 能提高协作效率;否则可能只是把复杂度集中到一个仓库里。

追问方向

  • pnpm workspace 如何管理依赖?
  • Monorepo 和多仓库如何取舍?
  • 什么是增量构建和远程缓存?

评分参考

  • 1 分:知道 Monorepo 是单仓多项目。
  • 2 分:能说出代码复用和统一规范。
  • 3 分:能指出构建和发布复杂度。
  • 4 分:能结合团队规模、CI、缓存、版本策略选型。

八、性能优化

Q41:前端性能优化可以从哪些方向入手?【中等】

考察点:系统性思考、指标意识、优化闭环。

参考答案

性能优化可以按链路拆解:网络加载、资源体积、渲染执行、交互响应、缓存策略、监控反馈

  • 网络层面:CDN、HTTP/2/3、缓存、预加载、减少请求、压缩。
  • 资源层面:代码分割、Tree Shaking、图片压缩、现代格式、字体子集化。
  • 渲染层面:减少重排重绘、虚拟列表、懒加载、避免长任务。
  • 交互层面:关注输入延迟、主线程占用、防抖节流、Web Worker。

更专业的回答要带指标。常见 Web Vitals 包括 LCP、INP、CLS:

  • LCP:最大内容绘制
  • INP:交互响应
  • CLS:布局稳定性

优化原则:不是凭感觉做,而是先采集指标,再定位瓶颈,最后验证效果。

追问方向

  • LCP、INP、CLS 分别代表什么?
  • 如何定位首屏慢?
  • 性能优化如何避免只优化实验室分数?

评分参考

  • 1 分:能说出压缩、懒加载等点。
  • 2 分:能按加载、渲染、交互分类。
  • 3 分:能提到 Web Vitals 指标。
  • 4 分:能建立监控、定位、优化、验证闭环。

Q42:什么是重排和重绘?如何减少它们?【简单】

考察点:浏览器渲染、DOM 操作优化。

参考答案

  • 重排(回流):元素几何信息发生变化后,浏览器需要重新计算布局。例如修改宽高、位置、字体大小、插入删除 DOM、读取某些布局属性等。
  • 重绘:元素外观变化但布局不变,例如颜色、背景、阴影变化。

重排通常比重绘成本更高,因为它可能影响后续节点甚至整个页面布局。

减少方式

  1. 批量修改 DOM,避免频繁读写布局属性交替发生。
  2. 使用 class 一次性改变样式。
  3. 对复杂动画使用 transformopacity
  4. 避免在循环中反复读取 offsetWidth 后又写样式。
  5. 长列表使用虚拟滚动。

定位工具:Performance 面板、Layout Shift、长任务、渲染帧率等。

追问方向

  • 哪些 CSS 属性更容易触发布局?
  • 为什么 transform 动画更流畅?
  • 什么是强制同步布局?

评分参考

  • 1 分:知道重排比重绘影响大。
  • 2 分:能区分布局变化和外观变化。
  • 3 分:能说出批量 DOM、transform 优化。
  • 4 分:能结合浏览器性能面板定位问题。

Q43:首屏加载慢如何排查和优化?【中等】

考察点:问题拆解、性能工具、工程经验。

参考答案

排查首屏慢要先看指标和瀑布图,而不是直接猜。可以用 Lighthouse、Performance、Network、线上 RUM 监控观察 TTFB、资源加载、JS 执行、LCP 元素、长任务等。

优化方向

  1. 服务端降低 TTFB,开启 CDN 和缓存。
  2. 压缩 HTML/CSS/JS,开启 gzip 或 br。
  3. 首屏 JS 代码分割,非关键模块懒加载。
  4. 关键 CSS 内联或优先加载。
  5. 图片使用 WebP/AVIF、响应式尺寸、懒加载。
  6. 字体使用 font-display
  7. 减少首屏接口数量,必要时做 SSR、SSG 或接口聚合。

针对性优化:如果 LCP 元素是大图,要重点优化图片加载优先级、尺寸和格式。如果瓶颈是 JS 执行长任务,要拆包、延迟非关键脚本、减少同步计算。

追问方向

  • 如何确认 LCP 元素是什么?
  • SSR 一定能提升首屏吗?
  • preloadprefetchpreconnect 的区别?

评分参考

  • 1 分:能说出压缩、懒加载。
  • 2 分:能使用 Network 看资源加载。
  • 3 分:能按 TTFB、资源、执行、渲染拆解。
  • 4 分:能针对 LCP 元素和长任务给出具体策略。

Q44:虚拟列表是什么?适合解决什么问题?【中等】

考察点:长列表渲染、滚动性能、DOM 数量控制。

参考答案

虚拟列表用于渲染超长列表时,只渲染可视区域附近的少量 DOM,而不是一次性渲染全部数据。用户滚动时,根据滚动位置动态计算应该显示哪些项,并用占位高度维持滚动条长度。

适用场景:几千、几万条数据的列表、日志、表格、聊天记录等。

核心收益

  • 减少 DOM 节点数量
  • 降低初始渲染成本
  • 减少滚动时布局压力

实现要点

  • 固定高度:通过 scrollTop / itemHeight 快速算出起始索引。
  • 动态高度:需要记录已测量高度、估算未测量高度,复杂度更高。

代价:SEO 不友好、浏览器查找只能查已渲染内容、动态高度处理复杂、无障碍和键盘导航需要额外处理。

追问方向

  • 固定高度和动态高度虚拟列表有什么区别?
  • 如何避免滚动白屏?
  • 表格虚拟滚动有哪些额外难点?

评分参考

  • 1 分:知道只渲染可视区域。
  • 2 分:能说出减少 DOM 数量。
  • 3 分:能解释滚动位置和索引计算。
  • 4 分:能分析动态高度、缓冲区、可访问性等问题。

九、项目设计与前端架构

Q45:如何设计一个通用请求库?【中等】

考察点:接口封装、错误处理、可维护性。

参考答案

通用请求库通常需要封装:

  1. 基础配置baseURLtimeoutheaders
  2. 请求拦截:注入 token、traceId、语言环境等。
  3. 响应拦截:统一解析业务状态码、处理未登录、权限不足、服务端错误。
  4. 错误处理:区分网络错误、超时、HTTP 错误、业务错误,不能全部简单弹一个"请求失败"。
  5. 并发场景:token 过期后多个请求同时返回 401,应该避免同时刷新 token,可以做刷新队列。
  6. 取消请求 :使用 AbortController 取消组件卸载后的请求,避免无效 setState

TypeScript 支持:请求库应支持泛型返回值,让调用方获得类型提示,但同时不能忽略运行时数据校验。

追问方向

  • 如何处理 token 无感刷新?
  • 请求取消和防重复提交怎么做?
  • 如何统一处理文件下载接口?

评分参考

  • 1 分:能封装 baseURL 和 token。
  • 2 分:能说出请求/响应拦截。
  • 3 分:能区分错误类型和登录失效。
  • 4 分:能处理并发刷新、取消请求、类型和监控。

Q46:后台管理系统的权限设计怎么做?【中等】

考察点:业务建模、路由权限、按钮权限。

参考答案

后台权限通常包括用户、角色、权限点、菜单、路由、按钮、数据范围。常见模型是 RBAC:用户绑定角色,角色绑定权限。

前端要处理三层权限

  1. 路由权限:根据用户权限生成可访问路由,未授权访问跳转 403 或登录页。
  2. 菜单权限:只展示用户可见菜单。
  3. 按钮/操作权限:例如新增、编辑、删除、导出。

数据权限:通常应由后端控制,前端只能做展示层辅助,不能把安全完全交给前端。即使前端隐藏了按钮,用户仍可能手动请求接口,所以接口层必须校验权限。

工程实现

  • 登录后获取用户信息和权限列表。
  • 前端将权限点映射为指令、Hook 或组件,用于控制按钮展示。
  • 保留兜底路由和异常页。

追问方向

  • 动态路由和静态路由过滤各有什么优缺点?
  • 按钮权限如何封装?
  • 为什么数据权限不能只在前端做?

评分参考

  • 1 分:知道根据角色控制页面。
  • 2 分:能说出菜单和路由权限。
  • 3 分:能补充按钮权限和后端校验。
  • 4 分:能设计完整 RBAC、异常页、权限点封装。

Q47:如何设计一个组件库?【偏难】

考察点:设计系统、组件 API、工程体系。

参考答案

组件库不是把项目里的组件复制出来就结束,它需要稳定的设计规范、API 设计、主题能力、文档、测试和发布流程。

设计层面

  • 定义颜色、字号、间距、圆角、阴影、动效等 Design Token,并和设计稿保持一致。
  • 组件层面关注受控/非受控、插槽或 render props、事件命名、可访问性、国际化、暗色模式、表单联动等。

工程层面

  • 支持按需引入、Tree Shaking、类型声明、样式隔离、版本管理、变更日志、单元测试、视觉回归测试和文档站。
  • 复杂组件还要考虑键盘操作、焦点管理、弹层层级、滚动锁定等细节。

目标:降低业务开发重复成本,同时保持一致体验,而不是制造一套难以维护的新框架。

追问方向

  • Button 组件 API 如何设计?
  • 组件库如何支持主题定制?
  • 如何保证组件升级不破坏业务?

评分参考

  • 1 分:知道组件库用于复用。
  • 2 分:能说出基础组件和文档。
  • 3 分:能考虑主题、按需引入、类型。
  • 4 分:能覆盖设计系统、测试、发布、兼容性和可访问性。

Q48:项目中如何做错误监控和日志上报?【中等】

考察点:稳定性建设、线上排查、监控体系。

参考答案

前端错误监控一般包括:

  • JS 运行时错误
  • Promise 未捕获错误
  • 资源加载错误
  • 接口错误
  • 框架错误边界
  • 白屏检测
  • 性能指标和用户行为链路

浏览器层面 :监听 window.onerrorunhandledrejection、资源 error 事件。

框架层面

  • React:使用 Error Boundary 捕获渲染阶段错误。
  • Vue:配置 errorHandler

上报内容

  • 错误信息、堆栈、页面 URL、用户标识、设备信息、浏览器版本、版本号、source map 映射、最近操作轨迹等。

重要:没有版本号和 source map,线上压缩代码的堆栈很难定位。同时要注意采样、去重、隐私脱敏和上报失败兜底。

追问方向

  • 如何捕获 Promise 未处理错误?
  • source map 上传后如何保护源码?
  • 白屏检测可以怎么做?

评分参考

  • 1 分:知道需要捕获错误。
  • 2 分:能说出 onerror 和接口错误。
  • 3 分:能补充版本号、source map、用户环境。
  • 4 分:能考虑采样、去重、隐私和稳定性闭环。

十、编码题与算法

Q49:手写防抖函数。【简单】

考察点:闭包、定时器、参数和 this。

基础实现

javascript 复制代码
function debounce(fn, delay = 300) {
  let timer = null;

  return function (...args) {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

这里通过闭包保存 timer。每次触发时清除上一次定时器,再重新设置。只有停止触发超过指定时间后,函数才会执行。

扩展 :可以补充立即执行、取消方法、返回值处理。注意 fn.apply(this, args) 是为了保留调用时的 this 和参数。

追问方向

  • 如何支持第一次立即执行?
  • 如何给防抖函数增加 cancel 方法?
  • React 中使用防抖为什么要注意函数引用稳定?

评分参考

  • 1 分:能写出定时器延迟。
  • 2 分:能清除上一次定时器。
  • 3 分:能保留参数和 this。
  • 4 分:能扩展立即执行、取消和框架场景。

Q50:手写节流函数。【简单】

考察点:高频事件控制、时间戳、定时器。

时间戳版本

javascript 复制代码
function throttle(fn, delay = 300) {
  let lastTime = 0;

  return function (...args) {
    const now = Date.now();
    if (now - lastTime >= delay) {
      lastTime = now;
      fn.apply(this, args);
    }
  };
}

这个版本第一次会立即执行,之后在间隔时间内忽略触发。定时器版本可以保证最后一次触发也有机会执行,更适合需要尾调用的场景。

两种实现差异:时间戳节流响应更直接,但可能丢掉最后一次;定时器节流能控制尾部执行,但实现稍复杂。真实业务里要根据交互选择 leading 和 trailing。

追问方向

  • 如何同时支持 leading 和 trailing?
  • 滚动事件里节流间隔设置多少合适?
  • requestAnimationFrame 能否用于节流?

评分参考

  • 1 分:能限制执行频率。
  • 2 分:能写出时间戳实现。
  • 3 分:能说明时间戳和定时器差异。
  • 4 分:能处理首尾执行和动画场景。

Q51:手写 Promise.all。【中等】

考察点:Promise、并发、顺序保持、错误处理。

javascript 复制代码
function promiseAll(iterable) {
  return new Promise((resolve, reject) => {
    const list = Array.from(iterable);
    const result = [];
    let count = 0;

    if (list.length === 0) {
      resolve([]);
      return;
    }

    list.forEach((item, index) => {
      Promise.resolve(item).then(
        value => {
          result[index] = value;
          count += 1;
          if (count === list.length) {
            resolve(result);
          }
        },
        reject
      );
    });
  });
}

关键点

  1. 入参可能不是 Promise,所以要用 Promise.resolve 包装。
  2. 结果顺序要和输入顺序一致,不能按完成顺序 push。
  3. 只要任意一个失败,整体就失败。

追问方向

  • Promise.allSettledPromise.all 有什么区别?
  • 如何实现并发数限制?
  • 空数组传给 Promise.all 返回什么?

评分参考

  • 1 分:知道全部成功才 resolve。
  • 2 分:能处理失败 reject。
  • 3 分:能保持结果顺序。
  • 4 分:能处理非 Promise 值、空数组、并发限制延伸。

Q52:手写深拷贝,要求处理循环引用。【中等】

考察点:递归、引用缓存、边界类型。

javascript 复制代码
function deepClone(value, cache = new WeakMap()) {
  if (value === null || typeof value !== 'object') return value;

  if (cache.has(value)) return cache.get(value);

  if (value instanceof Date) return new Date(value);
  if (value instanceof RegExp) return new RegExp(value);

  const result = Array.isArray(value) ? [] : {};
  cache.set(value, result);

  Reflect.ownKeys(value).forEach(key => {
    result[key] = deepClone(value[key], cache);
  });

  return result;
}
  • WeakMap 用于记录已经克隆过的对象,解决循环引用问题。
  • Reflect.ownKeys 可以拿到字符串 key 和 Symbol key,比 Object.keys 覆盖范围更大。

注意:这仍然不是工业级完整实现,因为还没有处理 Map、Set、函数、属性描述符、原型链等复杂情况。面试里能讲清边界,比假装"完整实现"更重要。

追问方向

  • 为什么用 WeakMap 而不是 Map
  • 如何处理 MapSet
  • 如何保留对象原型和属性描述符?

评分参考

  • 1 分:能递归复制对象。
  • 2 分:能区分数组和对象。
  • 3 分:能用 WeakMap 处理循环引用。
  • 4 分:能主动说明边界类型和工业实现复杂度。

Q53:实现数组扁平化。【简单】

考察点:递归、数组方法、边界处理。

递归版本

javascript 复制代码
function flatten(arr) {
  const result = [];

  arr.forEach(item => {
    if (Array.isArray(item)) {
      result.push(...flatten(item));
    } else {
      result.push(item);
    }
  });

  return result;
}

也可以使用原生 flat(Infinity)

javascript 复制代码
const result = arr.flat(Infinity);

面试建议:先写递归,再补充原生 API。递归版本简单直接,但极深嵌套可能造成调用栈溢出,可以用栈迭代方式优化。

追问方向

  • 如何按指定深度扁平化?
  • 如何用 reduce 实现?
  • 极深数组如何避免递归爆栈?

评分参考

  • 1 分:知道 flat
  • 2 分:能写递归实现。
  • 3 分:能支持指定深度。
  • 4 分:能考虑极深嵌套和性能。

Q54:如何实现 LRU 缓存?【偏难】

考察点:数据结构、Map、缓存淘汰策略。

LRU 是 Least Recently Used,最近最少使用缓存。容量满时,淘汰最久没有被访问的元素。

JavaScript 中可以借助 Map 的插入顺序实现:

javascript 复制代码
class LRUCache {
  constructor(capacity) {
    this.capacity = capacity;
    this.map = new Map();
  }

  get(key) {
    if (!this.map.has(key)) return -1;
    const value = this.map.get(key);
    this.map.delete(key);
    this.map.set(key, value);
    return value;
  }

  put(key, value) {
    if (this.map.has(key)) {
      this.map.delete(key);
    }
    this.map.set(key, value);

    if (this.map.size > this.capacity) {
      const oldestKey = this.map.keys().next().value;
      this.map.delete(oldestKey);
    }
  }
}

访问或更新某个 key 后,把它移动到 Map 末尾,表示最近使用。容量超出时删除 Map 的第一个 key。

追问方向

  • 为什么 Map 能保持插入顺序?
  • 如果不用 Map,如何用哈希表加双向链表实现?
  • LRU 在前端有哪些应用?

评分参考

  • 1 分:知道淘汰最近最少使用。
  • 2 分:能用 Map 实现基本功能。
  • 3 分:能保证 get/put 后更新顺序。
  • 4 分:能解释哈希表加双向链表的 O(1) 思路。

十一、移动端与跨端

Q55:移动端 1px 边框问题是什么?如何解决?【中等】

考察点:DPR、CSS 像素、移动端经验。

问题原因 :移动端 1px 问题源于设备像素比 DPR。CSS 中的 1px 是 CSS 像素,在 DPR 为 2 或 3 的高清屏上,会对应多个物理像素,视觉上可能显得比设计稿更粗。

常见方案 :使用伪元素加 transform 缩放:

css 复制代码
.hairline {
  position: relative;
}

.hairline::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: #ddd;
  transform: scaleY(0.5);
  transform-origin: 0 100%;
}

其他方案:viewport 缩放、border-imagebox-shadow、SVG 背景等。实际项目中伪元素方案较常见,兼容性和可控性都比较好。

追问方向

  • CSS 像素和物理像素有什么区别?
  • DPR 如何获取?
  • 安全区域 env(safe-area-inset-bottom) 用于什么场景?

评分参考

  • 1 分:知道高清屏边框会粗。
  • 2 分:能说出 DPR 原因。
  • 3 分:能写出伪元素缩放方案。
  • 4 分:能比较多种方案并结合安全区域处理。

Q56:移动端适配有哪些方案?rem、vw、响应式分别怎么选?【中等】

考察点:移动端布局、设计稿适配、响应式思维。

常见方案

  • rem 方案 :根据设计稿宽度动态设置根元素 font-size,再把 px 转成 rem。优点是兼容性好,适合传统 H5 活动页;缺点是全局依赖根字号,和第三方组件混用时要小心。
  • vw 方案 :直接基于视口宽度计算,写法简单,适合按屏幕比例缩放的页面。但在超宽、折叠屏、横屏场景要配合 max-width 或断点限制。
  • 响应式布局 :更关注不同设备下的信息结构变化,不只是等比缩放。对于后台系统、内容站、复杂表单,通常需要断点布局、弹性容器和组件级适配,而不是单纯 rem

追问方向

  • 为什么不能所有页面都等比缩放?
  • 横屏和折叠屏如何处理?
  • CSS Container Query 能解决什么问题?

评分参考

  • 1 分:知道 rem 或 vw。
  • 2 分:能说明按视口适配。
  • 3 分:能比较 rem 和 vw。
  • 4 分:能从内容结构、断点、容器查询角度设计响应式。

Q57:小程序、H5、App 跨端开发的主要差异是什么?【中等】

考察点:跨端认知、运行环境、技术选型。

  • H5:运行在浏览器或 WebView 中,能力受浏览器和容器限制。
  • 小程序:运行在平台提供的双线程架构中,逻辑层和渲染层分离,通过桥通信,API、包体积、路由、组件和样式都有平台约束。
  • App 原生:能力最强,但开发成本也更高。

跨端框架如 Taro、uni-app、React Native、Flutter 试图通过一套代码覆盖多个端,但没有银弹。多端差异包括组件能力、生命周期、路由、样式兼容、性能、原生 API、审核发布、调试工具等。

选型要看业务目标:营销页或轻交互,H5 足够;依赖微信生态能力,小程序更合适;追求复杂交互、稳定性能和深度原生能力,可能需要 RN、Flutter 或原生开发。

追问方向

  • 小程序为什么有包体积限制?
  • RN 和 Flutter 的渲染机制有什么差异?
  • 跨端项目如何处理平台差异代码?

评分参考

  • 1 分:知道不同端运行环境不同。
  • 2 分:能说出 H5 和小程序限制。
  • 3 分:能比较跨端框架优缺点。
  • 4 分:能基于业务、性能、生态和团队能力选型。

十二、AI、前沿技术与综合潜力

Q58:AI 工具会如何改变前端开发?前端工程师该保留什么核心能力?【简单】

考察点:技术视野、职业判断、学习能力。

参考答案

AI 工具已经能帮助前端完成代码生成、组件样板、测试用例、文档总结、错误排查、正则和脚本编写等任务。它提升的是执行效率,但不能替代工程判断。

前端工程师仍然需要保留几类核心能力:

  1. 需求理解和产品判断:知道用户真正要解决什么问题。
  2. 基础能力:理解浏览器、网络、JS、框架和工程化,不被生成代码牵着走。
  3. 架构和质量意识:能评估代码是否可维护、可测试、可演进。
  4. 审美和体验判断:能发现交互细节和性能问题。

面试表达:不要简单回答"AI 不会替代人"。更好的表达是:AI 会替代一部分重复编码,但会放大工程师之间在问题定义、系统设计、代码审查和落地负责上的差距。

追问方向

  • 你平时如何使用 AI 辅助开发?
  • AI 生成代码如何做质量检查?
  • 你认为前端未来三年会有哪些变化?

评分参考

  • 1 分:知道 AI 能辅助写代码。
  • 2 分:能说出提效场景。
  • 3 分:能指出仍需工程判断。
  • 4 分:能结合质量、架构、体验和职业发展表达独立观点。

Q59:Server Components、SSR、SSG、CSR 有什么区别?【偏难】

考察点:渲染模式、首屏、SEO、架构趋势。

参考答案

  • CSR(客户端渲染):浏览器下载 JS 后在客户端生成页面。优点是交互灵活、部署简单,缺点是首屏和 SEO 可能受影响。
  • SSR(服务端渲染):每次请求时服务端生成 HTML 返回给浏览器,首屏和 SEO 更好,但服务端压力更大,也要处理 hydration 成本。
  • SSG(静态生成):在构建时生成 HTML,适合内容相对稳定的页面,如文档、博客、营销页。它性能好、部署简单,但实时性较弱。
  • React Server Components(RSC):更细粒度的服务端组件模型。部分组件只在服务端执行,不把对应 JS 发送到客户端,可以减少包体积,并更直接访问服务端资源。但它改变了组件边界和数据获取方式,需要框架支持和团队理解成本。

追问方向

  • hydration 是什么?为什么会有成本?
  • SSR 一定比 CSR 快吗?
  • RSC 中客户端组件和服务端组件如何划分?

评分参考

  • 1 分:知道 CSR、SSR 基本区别。
  • 2 分:能说出 SSG 适合静态内容。
  • 3 分:能解释 hydration 成本。
  • 4 分:能理解 RSC 的包体积、数据访问和组件边界变化。

Q60:如果让你介绍一个最有代表性的项目,你该怎么讲?【简单】

考察点:项目表达、问题意识、个人贡献。

参考答案

项目介绍不要只背技术栈。一个清晰结构可以是:

  1. 项目背景:这是什么项目?
  2. 业务目标:为了解决什么问题?
  3. 你的角色:你负责什么?
  4. 核心难点:技术或业务上最难的点是什么?
  5. 技术方案:你是怎么解决的?为什么这样设计?
  6. 落地结果:上线后带来了什么变化?如何衡量?
  7. 复盘总结:如果重做一次,你会怎么改进?

示例:"这个项目是一个面向运营人员的配置平台,目标是把原来需要研发改代码的活动配置流程改成可视化搭建。我负责前端编辑器和预览链路。难点是组件拖拽、配置实时预览、表单校验和发布前校验。方案上我把页面抽象成 schema,用组件注册表渲染,编辑区和预览区共享一份状态。上线后活动配置从半天缩短到几十分钟,也减少了重复研发投入。"

核心:面试官更关心你有没有真正参与解决问题,而不是项目用了多少热门技术。你要主动讲清楚为什么这样设计、遇到什么坑、如何权衡、结果如何衡量。

追问方向

  • 项目里最难的问题是什么?
  • 如果重做一次,你会怎么改?
  • 这个项目如何保证质量和稳定性?

评分参考

  • 1 分:能说明项目做什么。
  • 2 分:能说出自己负责的模块。
  • 3 分:能讲清难点和方案。
  • 4 分:能讲出权衡、数据结果和复盘思考。

最后:应届生面试最容易丢分的 8 件事

  1. 只背结论,不讲原因。比如只说"用防抖",但讲不出为什么用、怎么实现、有什么边界。
  2. 只讲技术名词,不讲业务场景。面试官更想知道你能不能把技术用到项目里。
  3. 项目介绍像流水账。项目经历要突出你的角色、难点、方案和结果。
  4. 不承认边界。不会的问题可以说"我目前理解到这里",再给出推理方向,比硬编更好。
  5. 忽视浏览器和网络基础。前端不是只会框架,HTML、CSS、JS、HTTP 仍然是底盘。
  6. 过度包装项目。面试官连续追问三层,很容易判断你是不是真做过。
  7. 代码题不处理边界。空数组、异常输入、this、参数、返回顺序、异步失败都可能是加分点。
  8. 没有复盘意识。优秀候选人会主动讲"当时为什么这么做,现在看还有什么可以改"。

一套 7 天冲刺复习节奏

  • 第 1 天:HTML、CSS、浏览器渲染。目标是把布局、盒模型、BFC、缓存、跨域讲清楚。
  • 第 2 天:JavaScript 核心。重点是原型链、闭包、事件循环、Promise、this、深浅拷贝。
  • 第 3 天:TypeScript。重点是泛型、工具类型、unknown、接口建模和项目类型实践。
  • 第 4 天:React 或 Vue 主框架。不要两个都平均用力,优先把自己简历里写的框架讲深。
  • 第 5 天:工程化与性能。准备构建工具、规范工具、缓存策略、首屏优化、监控上报。
  • 第 6 天:代码题。防抖、节流、Promise.all、深拷贝、数组扁平化、LRU 至少手写一遍。
  • 第 7 天:项目复盘和模拟面试。把每个项目整理成 3 分钟版本和 8 分钟版本,准备追问。

结语

对 2026 届应届生来说,面试官通常不会要求你像资深工程师一样经历过大型系统的所有坑,但会非常关注三件事:基础是否扎实,表达是否清楚,遇到未知问题时是否能继续推理

真正有效的准备,不是把题库背到一字不差,而是把每个知识点都变成你能解释、能举例、能联系项目、能承认边界的表达。

如果你现在还有很多不会的题,不用慌。把问题拆开,按模块补齐,每天口述几道题,再回到项目里找对应场景。面试竞争到最后,拼的不是谁收藏的资料最多,而是谁能在 40 分钟里稳定展示自己的基本功、思考方式和成长速度。

祝你 2026 届校招顺利,拿到真正适合自己的前端 offer。

复制代码
相关推荐
aa小小2 小时前
localhost 访问异常排查笔记
前端
格子软件2 小时前
2026年GEO优化系统源码的分布式状态机深度拆解
java·前端·vue.js·vue·geo
陈随易2 小时前
Rust、Golang、MoonBit 编译成 WASM,体积和速度差距有多大?
前端·后端·程序员
IT_陈寒2 小时前
Python多线程的坑,我居然现在才踩到
前端·人工智能·后端
摇滚侠2 小时前
方法 A 等方法 B 执行完再执行 叫同步调用还是异步调用 JS 默认是同步调用还是异步调用
开发语言·javascript·ecmascript
触底反弹3 小时前
🔥 字符串算法面试三连击:反转、回文、回文变种,搞懂这三题稳了!
前端·javascript·算法
触底反弹3 小时前
AI Tool Use 深度解析:大模型是如何"突破物理限制"调用外部工具的?
javascript·人工智能·后端
竹林8183 小时前
从 RPC 超时到批量签名:我用 @solana/web3.js 重构了一个 NFT 铸造页面,踩了这些坑
前端·javascript
工业HMI实战笔记4 小时前
工业HMI界面布局“1核2辅”黄金结构,适配90%场景
前端·ui·性能优化·自动化·交互
优雅格子衫4 小时前
TypeScript 类的基本使用小结
javascript·ubuntu·typescript