前端面试题汇总及深度解析(2025最新版)
目录
HTML与CSS核心知识
### 1. BFC原理与应用场景
**问题**:什么是BFC?如何触发?典型应用场景有哪些?
**解析**:
BFC(Block Formatting Context)块级格式化上下文,是CSS渲染时的独立布局区域:
```css
.container {
overflow: hidden; /* 触发方式1 */
display: flow-root; /* 触发方式2(推荐) */
float: left; /* 触发方式3 */
}
核心特性:
- 内部盒子垂直排列
- 垂直方向margin合并
- 阻止元素被浮动覆盖
应用场景:
- 清除浮动(替代clearfix)
- 防止margin穿透
- 自适应两栏布局
2. CSS选择器权重计算
问题:计算以下选择器权重:
#nav .list li:hover
答案:
ID(1) + Class(1) + Element(1) + Pseudo-class(1) = 1,1,2
权重规则:
- 内联样式(1,0,0,0)
- ID选择器(0,1,0,0)
- 类/伪类/属性(0,0,1,0)
- 元素/伪元素(0,0,0,1)
JavaScript深度剖析
1. 闭包与内存泄漏
问题:解释闭包原理并说明可能引起的内存泄漏场景。
答案:
function createCounter() {
let count = 0;
return function() {
return ++count;
};
}
const counter = createCounter();
闭包三要素:
- 外层函数嵌套内层函数
- 内层函数引用外层变量
- 外层函数返回内层函数
内存泄漏场景:
- DOM元素引用未释放
- 定时器未清除
- 全局变量缓存
2. Event Loop执行机制
问题:分析以下代码执行顺序:
console.log(1);
setTimeout(() => console.log(2), 0);
Promise.resolve().then(() => console.log(3));
console.log(4);
执行过程:
- 同步任务:1 -> 4
- 微任务队列:3
- 宏任务队列:2
输出顺序:1 -> 4 -> 3 -> 2
原理图示:
[调用栈] -> 微任务队列 -> (渲染) -> 宏任务队列
React框架专题
1. Fiber架构核心原理
问题:React Fiber解决了什么问题?如何实现异步可中断更新?
关键点:
- 旧架构递归更新无法中断
- Fiber将虚拟DOM节点拆解为链表结构
- 使用requestIdleCallback分片执行
调度流程:
- Reconciliation阶段(可中断)
- Commit阶段(同步执行)
2. Hooks原理剖析
问题:useState如何在函数组件中保持状态?
实现机制:
- 通过链表结构存储hook状态
- 依赖调用顺序保证状态对应
- 每次render时获取当前hook节点
let hooks = [];
let currentHook = 0;
function useState(initial) {
hooks[currentHook] = hooks[currentHook] || initial;
const setState = (newVal) => {
hooks[currentHook] = newVal;
render();
};
return [hooks[currentHook++], setState];
}
前端工程化体系
1. Webpack Tree-shaking原理
生效条件:
- 使用ES Module语法
- 生产模式开启optimization.usedExports
- 配合Terser进行代码删除
配置示例:
module.exports = {
mode: 'production',
optimization: {
usedExports: true,
minimize: true
}
};
2. CI/CD流程设计
标准流程:
- 代码提交触发Git Hook
- ESLint + Unit Test
- 自动构建Docker镜像
- 灰度发布验证
- 全量部署
性能优化实践
1. 首屏加载优化方案
核心指标:
- FCP < 1.8s
- TTI < 3.5s
优化手段:
- 资源预加载(preload/prefetch)
- 代码分割(dynamic import)
- 服务端渲染(SSR)
- 图片懒加载 + WebP格式
算法与数据结构
1. 手写Promise.all
function promiseAll(promises) {
return new Promise((resolve, reject) => {
let results = [];
let completed = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(res => {
results[index] = res;
completed++;
if (completed === promises.length) {
resolve(results);
}
})
.catch(reject);
});
});
}