前端核心面试题详解
闭包
定义与原理
闭包(Closure)是指函数能够访问并记住其外部作用域中的变量,即使外部函数已经执行完毕。它由两部分组成:一个内部函数和该函数被创建时的词法环境。
function outer() {
let count = 0;
function inner() {
count++;
console.log(count);
}
return inner;
}
const counter = outer();
counter(); // 输出 1
counter(); // 输出 2
核心机制:
- 作用域链:函数定义时记录词法环境,访问变量时沿链向上查找。
- 变量持久化:内部函数持有外部变量引用,阻止垃圾回收。
常见用途
1. 私有变量封装 通过闭包隐藏内部状态,仅暴露操作接口:
function createCounter() {
let count = 0;
return {
increment: () => count++,
getValue: () => count
};
}
2. 函数柯里化 将多参数函数转换为单参数链式调用:
function add(a) {
return function(b) {
return a + b;
};
}
const add5 = add(5);
console.log(add5(3)); // 8
3. 事件处理 在监听器中保留上下文变量:
function setupButton() {
const button = document.getElementById('myButton');
let clicks = 0;
button.addEventListener('click', function() {
clicks++;
console.log(`按钮被点击了 ${clicks} 次`);
});
}
陷阱与解决方案
循环中的闭包问题
使用 var 声明的变量在循环中共享同一个引用,导致结果异常:
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 输出 3, 3, 3
}, 100);
}
解决:使用 let 或 IIFE 创建块级作用域隔离变量。
内存泄漏 闭包长期持有大对象引用会导致内存无法释放。需在不使用时解除引用:
leak = null; // 手动解除引用
事件循环(Event Loop)
JavaScript 是单线程语言,事件循环通过任务队列协作实现异步执行。
核心概念
- 调用栈:存储函数调用,后进先出。
- 任务队列:分为宏任务(Macro Task)和微任务(Micro Task)。
- 宏任务:
setTimeout,setInterval, I/O, UI 渲染。 - 微任务:
Promise.then,MutationObserver,process.nextTick。
- 宏任务:
执行流程
- 执行同步代码直到调用栈为空。
- 执行所有微任务。
- 执行一个宏任务。
- 重复上述步骤。
示例解析
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// 输出顺序:1 → 4 → 3 → 2
应用场景
- 异步编程避免回调地狱。
- 性能优化拆分耗时任务。
- 动画渲染配合
requestAnimationFrame。
BFC(块级格式化上下文)
BFC 是独立的渲染区域,内部布局不影响外部元素。
触发条件
- 根元素、
float不为none、position为absolute/fixed、display为inline-block/table-cell/flex/grid、overflow不为visible。
特性与应用
- 包含浮动:防止父元素高度塌陷。
- 避免外边距重叠:相邻元素 margin 不合并。
- 隔离布局:适合独立 UI 组件。
清除浮动示例
.parent { overflow: hidden; /* 触发 BFC */ }
内存泄漏
内存泄漏指已不再使用的内存未被释放,通常由不当引用管理引起。
常见场景
- 未释放缓存:Map/Cache 未及时清理。
- DOM 引用:移除 DOM 后仍持有引用。
- 闭包引用:闭包保留不必要的外部变量。
- 定时器/监听器:未清除
setInterval或addEventListener。 - 意外全局变量:未声明变量挂载到
window。
排查与预防
- 使用 Chrome DevTools Memory 面板分析 Heap Snapshot。
- 优先使用
WeakMap/WeakSet。 - 及时清除定时器和事件监听。
Vue 虚拟 DOM 与 MVVM
虚拟 DOM 用 JS 对象描述真实 DOM,通过 Diff 算法最小化更新开销。
- 优点:减少直接 DOM 操作,跨平台能力强。
- 局限:首次渲染有开销,不适合简单静态页。
MVVM 模式 Model-View-ViewModel 分离 UI 与业务逻辑。
- 双向绑定:数据变化自动更新视图。
- 命令绑定:用户操作触发 ViewModel 方法。
Vue2 与 Vue3 响应式原理
Vue2
使用 Object.defineProperty 劫持属性。
- 局限:无法检测新增/删除属性,数组索引修改需特殊处理。
Vue3
使用 Proxy 代理整个对象。
- 优势:全面拦截,支持新增/删除,性能更优。
对比
| 特性 | Vue2 | Vue3 |
|---|---|---|
| 劫持方式 | 属性劫持 | 对象代理 |
| 新增属性 | 不支持 | 支持 |
| 数组响应 | 重写方法 | 直接拦截 |
深拷贝与浅拷贝
- 浅拷贝:只复制第一层,引用类型共享地址(如
...obj,Object.assign)。 - 深拷贝:递归复制所有层级,完全独立(如
JSON.parse(JSON.stringify()),lodash.cloneDeep)。
注意:JSON 序列化无法处理函数、undefined、循环引用;手动递归需处理循环引用逻辑。
npm 依赖管理
开发依赖 (devDependencies)
仅用于开发环境(构建、测试),不发布到生产。
npm install eslint --save-dev
生产依赖 (dependencies)
项目运行必需,随项目发布。
npm install vue
版本符号
^:允许次版本更新(兼容变更)。~:仅允许修订版本更新(修复 bug)。
ES6 模块化
ES6 引入 import/export 静态模块系统。
- 特点:编译时加载,支持 Tree-shaking,严格模式。
- 导出:命名导出
export const或默认导出export default。 - 导入:
import { name } from 'module'或import mod from 'module'。
Vue key 的作用
key 用于唯一标识虚拟 DOM 节点,帮助 Diff 算法高效复用。
- 为什么不用 index:列表顺序变化时,index 会重新分配,导致节点错误复用或状态混乱。
- 最佳实践:使用唯一 ID 作为 key,避免动态生成随机值。
CSS 选择器优先级
权重从高到低:内联样式 > ID > 类/伪类 > 元素/伪元素。
- 计算:按位权相加,同权重后定义的覆盖前者。
- 建议:避免滥用
!important和 ID 选择器,多用类选择器。
JavaScript 阻塞与优化
JS 单线程,同步长任务会阻塞主线程。
- 表现:页面卡顿,交互无响应。
- 解决:
- 异步 API (
setTimeout,Promise)。 - Web Workers 后台处理。
- 任务分片执行。
requestAnimationFrame优化动画。
- 异步 API (
Promise 用法
Promise 解决回调地狱,提供链式调用。
- 状态:Pending -> Fulfilled/Rejected(不可逆)。
- 方法:
.then(),.catch(),.finally()。 - 静态方法:
all,race,allSettled。
大量数据处理策略
- 加载:分页、懒加载。
- 处理:Web Workers 分片处理,哈希表替代数组查找。
- 存储:IndexedDB 存大量数据,TypedArray 存数值。
- 渲染:虚拟列表,减少 DOM 操作。
兼容性处理
- 浏览器:Polyfill 新特性,Autoprefixer 加前缀,Babel 转译语法。
- 设备:媒体查询适配屏幕,Flex/Grid 布局。
- 操作系统:安全字体,正斜杠路径。
CSS 绘制椭圆
- border-radius:宽高不等且
border-radius: 50%。 - clip-path:
ellipse(50% 50% at 50% 50%)。 - SVG:
<ellipse>标签精确控制。
setTimeout vs setInterval
- setTimeout:延迟一次执行,设为 0 进入下一轮事件循环。
- setInterval:周期性执行,需注意回调堆积问题。
- 建议:递归使用
setTimeout替代setInterval保证间隔准确。
性能指标与检测
核心指标
- LCP, FID, CLS, TBT。
工具
- Lighthouse, WebPageTest, Chrome DevTools Performance 面板。
performance.now(),console.time。
HTTP 状态码
- 2xx:成功(200 OK, 201 Created)。
- 3xx:重定向(301, 302)。
- 4xx:客户端错误(400, 404)。
- 5xx:服务器错误(500, 502, 503)。
箭头函数 vs 普通函数
- this:箭头函数继承外层,普通函数指向调用者。
- arguments:箭头函数无,需用剩余参数。
- 构造:箭头函数不能作为构造函数。
防抖与节流
- 防抖 (Debounce):停止触发后执行,适用于搜索框输入。
- 节流 (Throttle):固定频率执行,适用于滚动事件。
宏任务与微任务
- 微任务:优先级高,当前宏任务后立即执行(Promise)。
- 宏任务:下一轮执行(setTimeout)。
- 目的:区分任务粒度,优化调度与用户体验。
跨域解决方案
- CORS:服务端设置响应头。
- JSONP:利用 script 标签(仅 GET)。
- 代理:后端转发请求。
- PostMessage:跨窗口通信。
加载速度优化
- 资源:压缩,CDN,图片格式优化(WebP)。
- 请求:合并文件,HTTP/2,雪碧图。
- 代码:Code Splitting, Tree Shaking, 懒加载。
- 缓存:Service Worker, Cache-Control。
页签消息传递
- localStorage:监听 storage 事件。
- BroadcastChannel:专用通道通信。
- SharedWorker:共享后台线程。
- postMessage:跨窗口通信。
元素水平居中
- Flexbox:
justify-content: center。 - Grid:
place-items: center。 - 绝对定位:
left: 50%; transform: translateX(-50%)。 - 行内元素:
text-align: center。
let, const, var
- 作用域:var 函数作用域,let/const 块级作用域。
- 提升:var 可访问 undefined,let/const 存在 TDZ。
- 声明:var 可重复,let/const 不可。
作用域与作用域链
- 作用域:变量可访问范围(全局/函数/块级)。
- 作用域链:变量查找机制,从当前作用域向上传递至全局。
继承方式
- 原型链:子类原型指向父类实例。
- 构造函数:call 父类构造函数。
- 组合继承:结合两者。
- 寄生组合:最优解,避免重复调用构造函数。
- ES6 Class:语法糖,底层仍是原型。
缓存与持久化
- HTTP 缓存:强缓存 (Cache-Control), 协商缓存 (ETag)。
- 本地存储:LocalStorage (持久), SessionStorage (会话), IndexedDB (结构化)。
require vs import
- require:CommonJS,动态加载,Node.js 原生。
- import:ES Modules,静态加载,编译时确定,支持 Tree-shaking。
px, em, rem
- px:绝对单位,固定大小。
- em:相对当前元素字体大小。
- rem:相对根元素字体大小,适合全局布局。
盒模型
- 标准:width 仅内容区。
- IE:width 包含 padding/border。
- 统一:
box-sizing: border-box。
ES6 新特性
变量声明、箭头函数、模板字符串、解构赋值、默认参数、扩展运算符、Class、Module、Promise、Symbol、迭代器等。
HTTP 缓存策略
- 强缓存:不发送请求,直接读取本地。
- 协商缓存:发送请求,服务器判断是否更新。
Vue Router 模式
- Hash:URL 含 #,无需服务器配置,兼容性好。
- History:URL 美观,需服务器配置支持 fallback。
JavaScript 缺点
单线程阻塞、弱类型风险、兼容性差异、安全性挑战、调试难度等。
原型与原型链
每个对象都有原型,属性查找沿原型链向上直至 null。
XSS 与 CSRF
- XSS:注入脚本,防御靠编码过滤、CSP、HttpOnly Cookie。
- CSRF:伪造请求,防御靠 Token、Referer 检查、SameSite。
HTTP 详解
请求/响应结构、方法 (GET/POST)、状态码、版本演进 (1.0/1.1/2/3)。
分片技术
大数据集分割处理,如数组分片、文件分片、任务分片,避免内存溢出或阻塞。
懒加载原理
延迟加载非关键资源,进入可视区再加载。可用 Intersection Observer 优化 scroll 监听。
脱离文档流
position: absolute/fixed, float, display: none 使元素脱离正常流。
堆与栈
- 栈:基本类型,函数调用栈,LIFO。
- 堆:引用类型,动态分配,GC 管理。
v-model 原理
语法糖,等价于 v-bind:value + @input 事件监听。
组件通信
Props/$emit, Event Bus, Provide/Inject, Vuex, $refs。
Diff 算法
同层比较,Key 优化列表更新,批量应用差异。
Webpack 配置
Entry, Output, Loader, Plugin, Mode。常用插件包括 Babel, HTMLWebpackPlugin, Terser。
URL 到页面呈现
DNS 解析 -> TCP 握手 -> HTTP 请求 -> 服务器响应 -> 渲染树构建 -> 执行 JS。
前端优化总结
减少请求、利用缓存、代码压缩、图片优化、渲染性能调优、SEO 增强。

