前端面经 
CSS 的盒模型 
有普通盒模型与怪异盒模型,普通盒模型宽度是内容区域,box-sizing:border-box 设置为怪异盒模型,宽度包含 padding+border
CSS 选择器优先级 
ID > class > 元素。内联样式优先级最高,!important 可覆盖但应慎用。
CSS 继承 
某些属性(如 font-family、color)会从父元素继承;inherit 可以设置某个属性继承上级,unset 可以取消继承。
CSS 元素隐藏 
display,visibility(不可见但保留占位),opacity,transform 缩放,宽高 0 overflow: hidden;
position: absolute; left: -9999px; 等等
闭包 
- 解决的问题: 函数作用域中的变量在函数执行后不被销毁,也能在函数访问内部的变量。
 - 闭包带来的问题: 闭包中变量不会销毁,会内存泄露,容易导致内存溢出。
 - 闭包的应用: 能够模仿块级作用域,能够实现柯里化,在构造函数中定义特权方法、Vue 中数据响应式 Observer 中使用闭包等。
 
补充: 柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
垂直居中 
Flex 和 Grid,老项目用定位 + transform。
BigInt 和 Synbol 区别 
- BigInt 是表示任意精度整数的数值类型,用来做超出 Number 精度范围的整数运算;
 - Symbol 是表示唯一标识符的原始类型,常用作对象的私有/唯一属性键。
 - BigInt 支持加减乘除等整数运算,但不能与 Number 隐式混合(需要显式转换),也不能用于 Math 系列函数;
 - Symbol 不能做算术或字符串隐式拼接,不能被隐式转换为字符串。
 
== 和 === 区别 
- == 是抽象相等,会在比较前做类型转换;
 - === 是严格相等,不做类型转换,类型和值都必须相等
 
箭头函数 
- 没有自己的 this,使用定义时外层作用域的 this
 - 没有自己的 arguments、super、new.target
 - 不可用 new 实例化,且没有 prototype
 - 不能使用 function* 或 yield
 
浏览器缓存 
- HTTP 缓存(强制缓存):通过 Cache-Control / Expires 控制资源在客户端可直接使用的时长
 - 协商缓存(验证缓存):通过 ETag / Last-Modified 配合 304 Not Modified 验证更新,节省带宽
 - 浏览器缓存层级(内存缓存 vs 磁盘缓存):热点资源可能存在内存或磁盘,301 状态
 
可答:
- CDN/中间缓存
 - 客户端存储:localStorage/sessionStorage/IndexedDB (离线或数据缓存,但非浏览器资源缓存机制)。
 - 资源预取/预加载:
<link rel="preload|prefetch|prerender"> 
跨域 
协议/域名/端口 任一不同都会产生跨域。
解决方式:
- 服务器返回 Access-Control-Allow-* 响应头允许跨域
 - 服务器 Nginx 反向代理
 - JSONP
 
开发时配置 vite webpack 代理解决
Vue2 和 Vue3 区别 
- Vue2 以 Options API 为主;Vue3 引入 Composition API
 - Vue2 用 Object.defineProperty(对新增/删除属性有局限,需要 $set);Vue3 用 Proxy 都能监听数据变化。
 - Vue3 重写并优化了虚拟 DOM 和渲染流程,运行更快、初始包更小并支持更好 tree-shaking
 - Vue3 支持了 TS
 - Vue3 新组件:Fragment(组件不需要最外层有根节点)、Teleport(传送:组件渲染到组件外的任意位置)、Suspense(异步组件占位),这些 Vue2 原生没有
 
vue 和 react 区别 
- 模板/语法:Vue 是 html+指令(也支持 JSX);React 使用 JSX,把 html 写成 js
 - 响应式模型:Vue 自动追踪依赖;React 采用不可变状态更新并通过重新渲染驱动视图(useState/useReducer)。
 - 组件组织:Vue 支持 Options API 与 Composition API;React 以函数组件 + Hooks 为主,强调通过 Hook 组合逻辑。
 - 数据流:Vue 原生支持双向绑定(v-model);React 是单向数据流,双向需显式处理。
 
登录流程 
- 客户端提交账号/密码 或 第三方授权。
 - 服务器验证通过后签发凭证(Session ID 或 Token)。
 - 服务端可以使用 Set-Cookie httpOnly+Secure 设置凭证,或返回短期访问 Token 并配合刷新 Token
 
节流防抖 
防抖是延迟执行,连续触发只执行最后一次;
节流是限频执行,间隔时间内只执行一次。
防抖:搜索框输入、窗口 resize、表单校验
节流:滚动加载、按钮点击防止连点、页面滚动事件
图片压缩 
图片压缩可以在 前端、后端、构建工具、CDN 多个环节实现,常见方式有 格式优化、有损/无损压缩、懒加载和响应式加载。
大文件上传 
大文件上传一般用 分片 + 并发 + 断点续传 + 秒传 的组合方案
- 断点续传:将文件切分为小块上传,失败后只需重传丢失部分,适合大文件或网络不稳定。
 - 分片上传:前端切片 + 后端合并,常见实现是前端 File API (slice 方法)切片,服务端记录分片信息并最终合并。
 - 秒传(快速上传):通过文件的哈希值(MD5/SHA1)判断是否已存在,存在则直接返回成功。
 
虚拟 dom 
- Vue 的虚拟 DOM 是用 js 对真实 DOM 的抽象表示,用对象来描述节点和结构。
 - 更新时先生成新的虚拟 DOM,再和旧的做 diff 算法比较,最后只更新变化的部分,提升性能和跨平台能力。
 
小程序和 h5 的区别 
小程序运行在各个平台的容器里,依赖平台提供的 API,不能完全脱离平台;
H5 基于浏览器运行,更开放但性能相对差。
小程序体验接近原生,入口流量好,但受平台限制;
H5 跨平台性好,更新方便,但在性能和系统能力调用上不如小程序。
页面多请求并发,如何保证每次都是 n 个请求在并发 
“核心就是控制同时进行的请求数,保证始终保持 n 个在跑。答案如下:”
- Promise 并发池:维护一个固定大小的请求池,每次请求完成后再加入新的请求。
 - 队列控制:先将请求放入队列中,按并发数取出执行,完成后再取新的。
 - 第三方库:如 p-limit、async 库等来限制并发数。
 
React Hooks 相关 
| Hook 名称 | 面试解释(简洁) | 典型场景 | 
|---|---|---|
| useState | 声明状态,返回状态值和更新函数 | 组件内部状态管理 | 
| useEffect | 处理副作用,依赖数组控制触发 | 数据请求、订阅、定时器 | 
| useContext | 获取上下文值,无需层层传 props | 跨组件状态共享 | 
| useReducer | 状态管理,适合复杂状态或替代 Redux | 多状态逻辑复杂组件 | 
| useCallback | 缓存函数引用,避免子组件重复渲染 | 传给子组件或依赖数组函数 | 
| useMemo | 缓存计算值,避免重复计算 | 性能优化,依赖变化重算 | 
| useRef | 保存引用/DOM 节点,更新不触发渲染 | 操作 DOM 或保持变量跨渲染 | 
| useImperativeHandle | 自定义暴露给父组件的实例方法 | forwardRef 场景,自定义暴露 API | 
| useLayoutEffect | 同步副作用,DOM 更新后、浏览器绘制前 | 测量布局或同步 DOM | 
| useDebugValue | 给自定义 Hook 打印调试信息 | 调试自定义 Hook | 
| useTransition | 标记非紧急更新,实现界面过渡 | 优化渲染延迟、并发特性 | 
| useDeferredValue | 延迟值更新,避免高频渲染 | 输入框防抖、界面流畅优化 | 
| useId | 生成唯一 ID,服务端渲染安全 | 表单元素 id、组件唯一标识 | 
| useSyncExternalStore | 订阅外部 store,兼容 Concurrent Mode | Redux/自定义状态管理 | 
| useInsertionEffect | DOM 变更前同步注入样式 | 样式库或 CSS-in-JS 优化 | 
useState 
状态钩子,可以用来管理组件内的状态。返回数组[当前值,更新函数]
useEffect 
第一个参数是函数,返回函数可以模拟 Vue unmounted,第二个参数是依赖数组,只有当数组变化时才会执行。
- 空数组 [] → 只在挂载和卸载执行一次。
 - 指定依赖 [dep1, dep2] → 当依赖变化时执行。
 - 不写依赖 → 每次渲染都执行(慎用,性能可能受影响)。
 
useContext 
- createContext 创建 Context,组件树上用 Context.Provider 提供状态,子组件通过 useContext(MyContext) 获取状态和方法
 
useReducer 
比 useState 更适合处理状态逻辑较复杂或依赖前一个状态的场景。
useReducer 接受函数(内部修改状态)和初始状态,返回数组[当前状态,dispatch 函数],可以用来管理复杂的状态。
useCallback 
- 如果不用 useCallback 返回的变量函数,父组件每次渲染都会导致使用这个变量的子组件重新渲染
 - useCallback 可以缓存函数实例,配合 React.memo 避免子组件重复渲染
 - useCallback 第二个参数空数组,始终复用同一个函数
 
useMemo 
- useMemo 缓存计算值,避免重复计算,依赖变化时才重新计算
 
两个参数:一个返回值的函数和依赖数组
useImperativeHandle 
子组件用 forwardRef 包裹,useImperativeHandle 定义暴露给父组件的实例方法。
useImperativeHandle(ref, createHandle, deps)
vite 比 webpack 快在哪里 
- 冷启动快
 
- Webpack 启动时要先打包整个项目包括依赖和源码
 - Vite 利用浏览器原生 ESM,启动时不需要整体打包
 
- 热更新(HRM)快
 
- Webpack:代码改动后,需要重新打包依赖的模块
 - Vite:改动哪个文件就只编译哪个文件
 
简答:Vite 比 Webpack 快,主要是因为开发环境不需要整体打包,启动时只对依赖做一次 esbuild 预构建,源码按需编译;改动时只重新编译变动的文件,热更新速度更快。而 Webpack 启动和更新都要打包整个依赖图,所以慢。
git 发版流程 
- 生产分支拉出 feture 分支开发
 - 提交 PR 到 develop 分支
 - CICD自动化构建测试
 - 符合发版后合并到生产打上Tag
 
写了10次commit之后,发现写错分支了,怎么办 
git reset --mixed [HASH\]reset到出错前的commit,之前的commit会变为未跟踪状态git stash把改动暂存git checkout [分支名]切换到正确的分支git stash pop恢复暂存的改动
有没有了解cicd 
当代码 push 到远程仓库后,对代码进行自动构建、测试及部署等
公司内有用到k8s,gitlab的CICD,也有用过 GitHub Actions,vercel等
Node 高并发 
- Node 用事件循环+非阻塞 I/O,适合大量并发的 I/O 密集型请求(API、静态文件、长连接)。
 - 不适合长时间的 CPU 密集任务(会阻塞事件循环),这类要用 worker_threads、子进程或外部任务队列处理。
 - 单进程不能利用多核 → 用 Cluster / PM2 / Kubernetes 副本数 + 负载均衡。
 - 长连接(WebSocket/SSE)会占用文件描述符和内存,需提前规划连接容量与心跳/超时机制。
 
doker有了解多少 
- 开发和测试时,经常会有环境版本不一致的问题,用 Docker 可以配置统一的环境
 - 打包后可以放到容器里方便一键部署
 - CI/CD 可以把代码自动构建成镜像发到服务器
 
移动端怎么调试 
- 用vconsole插件,可以看到手机端的console日志
 - 小程序时用开发者工具的模拟器和真机调试功能
 
移动端优化 
- 性能优化:代码层面做按需加载、资源压缩,图片用 WebP、懒加载,减少首屏请求,接口合并,尽量用缓存。
 - 体验优化:提升交互流畅度,比如避免 300ms 点击延迟、用骨架屏、loading 占位,让用户觉得不卡。
 - 网络优化:弱网环境下用断点续传、接口重试、数据预加载,CDN 加速静态资源。
 
埋点 
- 手动埋点:自己在代码里写事件上报,比如 onClick 里发请求。
 - 可视化埋点:通过第三方工具在后台配置,不改代码就能埋点。
 - 无埋点:自动采集所有事件,后端再过滤分析。
 
埋点发请求,服务器挂了怎么办
- 上报的时候加 try-catch,别让埋点报错影响正常功能。
 - 一般会把数据放到消息队列(或者浏览器本地存储),等服务器恢复再重试。
 - 而且埋点请求通常是异步的,失败了就丢弃,不影响用户体验。
 
性能监控 
- 采集:用 Performance API 采集首屏时间、白屏时间、FCP、LCP、接口耗时、资源加载情况等。
 - 上报:通过 fetch 或者 new Image() 把数据上报到埋点平台,保证不影响用户正常使用。
 - 分析优化:后台汇总后看报表,比如首屏慢,就做资源压缩、懒加载;接口慢,就加缓存或并发优化。
 
服务器性能监控 
- CPU、内存、磁盘、网络 图形化监控:Prometheus + Grafana、Zabbix、Datadog
 - 服务状态和日志,监控进程是否挂掉、端口是否正常,接口错误率和响应时间。
 
静态资源优化 
- 文件压缩和图片格式优化,GZip压缩,Webp 图片
 - 缓存策略 静态资源加缓存(Cache-Control / ETag),让浏览器复用资源
 - 按需加载和懒加载,JS 分包、路由、模块、图片、组件动态加载
 
怎么减少重绘重排 
- 减少 DOM 操作,批量操作 DOM避免频繁修改。
 - 使用 CSS 动画替代 JS 动画
 - 减少布局计算和样式变动,频繁读取会触发重排的属性(如 offsetHeight、scrollTop)
 - 用 class 或 CSS 变量 批量修改样式
 
移动端click 300毫秒延迟 
浏览器默认的行为,比如双击缩放、双击滚动导致延迟
解决
- fastclick插件,用来规避click事件
 - touchend代替tap事件并阻止掉touchend的默认行为preventDefault()
 
键盘挡住输入框内容 
- 监听是否触发input。如果触发input框 就把固定定位
 - 绑定窗口改变事件,监听键盘的弹出,改变固定定位元素的位置
 
小程序的支付流程 
wx.login 获取临时登录凭证服务器交换用户信息(access_token、openid和session_key),然后调用统一下单API获取支付参数,使用wx.requestPayment()发起支付请求,用户确认后完成支付。
uni-app的理解 
写一套代码,可以发布到IOS、Android、Web(响应式)、以及各种小程序、快应用等多个平台
uni中不同平台设置不同的代码 
以 #ifdef 或 #ifndef 加平台代值开头,以 #endif 结尾
小程序分包 
减小首包体积::避免用户在首次打开小程序时需要下载过大的代码包
app.json文件中的subpackages字段下配置子包的路径
发版后,如何通知用户更新 
- 浏览器缓存:通过版本号或 hash 控制资源缓存,检测到新版本后弹提示或自动刷新,编译完成后buildEnd、webpack.Plugin 写入版本号