2026前端面试必杀技:大白话详解高频面试题
2026前端面试必杀技:大白话详解高频面试题
这篇全是大白话、超详细,覆盖HTML/CSS、JS基础/进阶、框架、网络、工程化、性能、手写题、项目8大模块,2026年高频题全覆盖,看完直接上战场。
一、HTML/CSS 基础(必问,占比30%)
1. 怎么实现元素水平+垂直居中?(必考)
大白话回答:
现在主流就3种,优先用Flex/Grid,老项目用绝对定位+transform。
- Flex(最常用):给父元素设
display: flex; justify-content: center; align-items: center,子元素直接居中,兼容性好、代码少。 - Grid(最简洁):父元素
display: grid; place-items: center,一行搞定。 - 绝对定位+transform(兼容老浏览器):父元素
position: relative,子元素position: absolute; left:50%; top:50%; transform: translate(-50%, -50%)。
2. 什么是BFC?有啥用?
大白话回答:
BFC就是块级格式化上下文,简单说就是一个“独立的渲染小房间”,里面的元素布局不会影响外面,外面也影响不到里面。
- 触发条件(满足一个就行):根元素html、float不为none、position是absolute/fixed、overflow不是visible、display是flex/grid/inline-block。
- 作用:解决浮动塌陷(父元素包不住浮动子元素)、外边距重叠(两个相邻块级元素margin会合并)、清除浮动影响。
3. 盒模型是什么?标准盒和怪异盒区别?
大白话回答:
盒模型就是元素的“盒子”,由**内容+内边距(padding)+边框(border)+外边距(margin)**组成。
- 标准盒(W3C):
box-sizing: content-box,width/height只算内容区,padding和border会撑大盒子。 - 怪异盒(IE):
box-sizing: border-box,width/height包含内容+padding+border,盒子大小固定,开发更方便,现在默认都用这个。
4. CSS选择器优先级怎么算?
大白话回答:
优先级从高到低:!important > 行内样式 > ID选择器 > 类/属性/伪类 > 标签/伪元素 > 通配符*。
- 计算规则:(0,0,0,0),分别对应行内、ID、类、标签,数值大的优先级高;优先级相同,后面的覆盖前面的。
二、JavaScript 基础(核心,占比40%)
1. var/let/const 区别?(必考)
大白话回答:
- 作用域:var是函数级({}包不住),let/const是块级(if/for/while的{}都能限制)。
- 变量提升:var会提升,声明前用是undefined;let/const也提升,但有暂时性死区(TDZ),声明前用直接报错。
- 重复声明:var可以重复声明,后面覆盖前面;let/const同一作用域不能重复声明。
- 赋值:var/let可以先声明后赋值、也能改值;const必须声明时赋值,且基本类型不能改值,引用类型(对象/数组)能改内部属性,但不能改引用地址。
- 开发习惯:优先用const,需要改值用let,尽量不用var。
2. 什么是闭包?作用+缺点?(必考)
大白话回答:
闭包就是函数套函数,内层函数引用了外层函数的变量,且内层函数被外部调用,导致外层函数的变量不会被垃圾回收。
- 作用:①数据私有化(封装工具,避免全局污染);②保存状态(比如防抖节流、计数器);③延迟执行(定时器/回调里用外层变量)。
- 缺点:内存泄漏(变量长期占内存),解决:不用时把引用设为null,组件卸载清定时器/事件监听。
- 例子:
functionouter(){letcount=0;returnfunctioninner(){count++;console.log(count);};}constadd=outer();add();// 1add();// 2 // count被保存,不会被回收3. this指向怎么确定?(必考)
大白话回答:
this指向谁调用它,就指向谁,分5种场景:
- 全局/普通函数:非严格模式指向window,严格模式是undefined。
- 对象方法:指向调用方法的对象。
- 构造函数:指向new出来的实例。
- 箭头函数:没有自己的this,继承外层作用域的this(最常用,解决回调里this丢失问题)。
- bind/call/apply:手动绑定this,优先级最高。
4. 原型和原型链是什么?(必考)
大白话回答:
- 原型(prototype):每个函数都有
prototype属性,是个对象,存实例共享的方法/属性。 - proto:每个对象(包括实例)都有
__proto__,指向构造函数的prototype。 - 原型链:实例的
__proto__往上找,直到Object.prototype.__proto__(null),这条链就是原型链,作用是实现继承、方法共享。 - 例子:数组实例能调用push,因为
arr.__proto__ === Array.prototype,push在Array.prototype里。
5. 浅拷贝vs深拷贝?怎么实现?(必考)
大白话回答:
- 浅拷贝:只拷贝一层,嵌套的引用类型(对象/数组)拷贝的是地址,改拷贝后的会影响原数据。
实现:Object.assign()、扩展运算符...、Array.slice()、Array.concat()。 - 深拷贝:拷贝所有层级,嵌套引用类型重新创建,改拷贝后的不影响原数据。
实现:①简单场景:JSON.parse(JSON.stringify())(缺点:丢函数/undefined/Symbol/Date);②复杂场景:手写递归深拷贝;③第三方:lodash.cloneDeep()。 - 手写浅/深拷贝示例:
// 浅拷贝functionshallowCopy(obj){if(typeofobj!=='object'||obj===null)returnobj;constnewObj=Array.isArray(obj)?[]:{};for(letkeyinobj){if(obj.hasOwnProperty(key))newObj[key]=obj[key];}returnnewObj;}// 深拷贝(基础版)functiondeepCopy(obj,cache=newWeakMap()){if(typeofobj!=='object'||obj===null)returnobj;if(cache.has(obj))returncache.get(obj);// 解决循环引用constnewObj=Array.isArray(obj)?[]:{};cache.set(obj,newObj);for(letkeyinobj){if(obj.hasOwnProperty(key))newObj[key]=deepCopy(obj[key],cache);}returnnewObj;}6. 作用域和作用域链?
大白话回答:
- 作用域:变量/函数的可访问范围,分全局作用域、函数作用域、块级作用域(let/const)。
- 作用域链:查找变量时,先在当前作用域找,找不到就往上一级作用域找,直到全局作用域,这条查找链就是作用域链,保证变量按规则访问。
三、JavaScript 进阶(中高级必问)
1. 异步编程有哪些方式?(必考)
大白话回答:
从老到新,解决“回调地狱”:
- 回调函数:最早的方式,嵌套多了变“回调地狱”(难读难维护)。
- Promise:ES6推出,链式调用
.then(),解决回调嵌套,状态:pending/fulfilled/rejected。 - Generator:可以暂停/恢复执行,配合
yield,用co库自动执行。 - async/await:ES8,Promise的语法糖,同步写法写异步,最常用,代码最清晰。
2. Promise 原理+常用方法?
大白话回答:
- 原理:Promise是一个容器,存异步操作结果,有三种状态,状态一旦改变就固定(pending→fulfilled/rejected),不会再变。
- 常用方法:
Promise.all():所有Promise成功才成功,一个失败就失败。Promise.race():谁先完成(成功/失败)就返回谁。Promise.allSettled():所有Promise完成(不管成功失败),返回每个结果。Promise.resolve()/Promise.reject():快速创建成功/失败的Promise。
3. 事件循环(Event Loop)?宏任务vs微任务?(必考)
大白话回答:
JS是单线程,异步任务靠事件循环执行,分宏任务和微任务:
- 宏任务:script整体、setTimeout、setInterval、I/O、UI渲染。
- 微任务:Promise.then/catch/finally、async/await、MutationObserver、queueMicrotask。
- 执行顺序:
- 执行同步代码;
- 清空当前所有微任务;
- 执行一个宏任务;
- 重复2→3,直到所有任务完成。
- 口诀:同步先跑,微任务清完,再跑一个宏任务。
4. 防抖vs节流?区别+实现?(必考)
大白话回答:
都是减少高频事件触发(比如scroll、resize、input),场景不同:
- 防抖(Debounce):最后一次触发后延迟执行,比如搜索框输入,停止输入500ms再发请求。
- 节流(Throttle):固定时间内只执行一次,比如滚动加载,每隔300ms执行一次。
- 实现代码:
// 防抖functiondebounce(fn,delay){lettimer=null;returnfunction(...args){clearTimeout(timer);timer=setTimeout(()=>fn.apply(this,args),delay);};}// 节流functionthrottle(fn,delay){letlastTime=0;returnfunction(...args){constnow=Date.now();if(now-lastTime>=delay){fn.apply(this,args);lastTime=now;}};}5. 垃圾回收机制?内存泄漏场景?
大白话回答:
- 垃圾回收:JS自动回收不再使用的内存,V8用标记清除(标记可达对象,清除不可达)和引用计数(有引用就不回收,循环引用有问题)。
- 内存泄漏场景:闭包滥用、全局变量过多、定时器/事件监听没清、DOM引用没删、缓存没控制。
四、框架(React/Vue,必问)
1. React 核心:虚拟DOM+Diff算法?
大白话回答:
- 虚拟DOM:用JS对象模拟真实DOM,操作虚拟DOM比操作真实DOM快(DOM操作耗性能)。
- Diff算法:对比新旧虚拟DOM,只更新变化的部分,减少DOM操作。React 16+用Fiber架构,支持可中断渲染,避免长时间阻塞主线程。
2. React Hooks:useState/useEffect/useCallback/useMemo?
大白话回答:
- useState:函数组件里存状态,返回
[状态, 修改状态的函数]。 - useEffect:处理副作用(异步、DOM操作、订阅),第二个参数是依赖项,依赖变才执行;空数组只执行一次(类似componentDidMount)。
- useCallback:缓存函数,避免子组件不必要重渲染(配合React.memo)。
- useMemo:缓存计算结果,避免重复计算(比如复杂列表过滤)。
3. Vue3 vs Vue2 响应式原理?(必考)
大白话回答:
- Vue2:用
Object.defineProperty,只能监听对象属性的读写,数组要重写push/pop等方法,不能监听新增/删除属性、数组索引修改。 - Vue3:用
Proxy,能监听整个对象/数组,支持新增/删除属性、数组索引修改,性能更好、功能更强。
4. Vue3 Composition API vs Options API?
大白话回答:
- Options API:按选项分(data/methods/computed),代码分散,大型项目难维护。
- Composition API:按逻辑功能组织(比如一个功能的状态、方法放一起),代码聚合,复用性强,适合大型项目,和React Hooks思想类似。
5. React vs Vue 区别?
大白话回答:
- 模板vs JSX:Vue用模板(HTML+指令),更直观;React用JSX(JS写UI),更灵活。
- 响应式:Vue自动追踪依赖,自动更新;React靠setState手动触发更新,需要优化(useCallback/useMemo)。
- 生态:React生态更丰富(Next.js、Redux);Vue更轻量,上手快,Vue3+Vite开发体验好。
五、网络(必问,占比15%)
1. HTTP 缓存?强缓存vs协商缓存?(必考)
大白话回答:
缓存就是把资源存本地,下次直接用,减少请求,分两种:
- 强缓存:不用发请求,直接用本地缓存。
响应头:Cache-Control: max-age=3600(优先级高)、Expires。 - 协商缓存:发请求问服务器,资源没改就返回304,用本地缓存;改了返回200+新资源。
响应头:Last-Modified/If-Modified-Since(时间)、ETag/If-None-Match(哈希,更准确)。
2. HTTP1.1/HTTP2/HTTP3 区别?
大白话回答:
- HTTP1.1:队头阻塞(一个请求阻塞,后面都等),连接复用(keep-alive),但同一域名最多6-8个连接。
- HTTP2:多路复用(一个连接并发多个请求,解决队头阻塞),头部压缩,服务器推送。
- HTTP3:用QUIC协议(UDP),彻底解决队头阻塞,连接迁移更快,适合移动端。
3. 跨域是什么?怎么解决?(必考)
大白话回答:
跨域是浏览器同源策略限制:协议、域名、端口有一个不同,就不能发请求/读响应。
- 解决方法:
- CORS(最常用):服务器设置响应头
Access-Control-Allow-Origin。 - JSONP:只支持GET,利用script标签跨域,现在少用。
- 代理服务器:开发用webpack-dev-server代理,生产用Nginx反向代理。
- postMessage:iframe之间跨域通信。
- CORS(最常用):服务器设置响应头
4. TCP 三次握手+四次挥手?
大白话回答:
- 三次握手(建立连接):
- 客户端发“我要连你”(SYN);
- 服务器回“我收到了,你连吧”(SYN+ACK);
- 客户端回“我知道了,开始传数据”(ACK)。
- 四次挥手(断开连接):
- 客户端发“我传完了,要断了”(FIN);
- 服务器回“我收到了,等我传完”(ACK);
- 服务器发“我也传完了,断吧”(FIN);
- 客户端回“我知道了,断开”(ACK)。
六、工程化+性能优化(中高级必问)
1. Webpack 优化?(必考)
大白话回答:分构建速度和打包体积优化:
- 构建速度:
- 多进程:
thread-loader处理babel,加快编译; - 缓存:
cache: { type: 'filesystem' },二次构建快60%+; - 缩小范围:
include/exclude,只处理src,跳过node_modules。
- 多进程:
- 打包体积:
- Tree Shaking:生产模式自动删未用代码;
- 代码分割:
splitChunks提取公共依赖(react/vue); - 资源压缩:JS用terser,图片用image-webpack-loader;
- 懒加载:
import()动态导入,按需加载页面。
2. 前端性能优化手段?(必考)
大白话回答:从网络、渲染、代码、资源四方面:
- 网络优化:HTTP缓存、CDN、资源压缩、懒加载、预加载、减少请求数(合并CSS/JS、雪碧图)。
- 渲染优化:减少DOM操作、虚拟列表(处理大量数据)、避免重排重绘、CSS用GPU加速(transform/opacity)。
- 代码优化:防抖节流、避免内存泄漏、React/Vue用memo/useCallback/useMemo、减少不必要重渲染。
- 资源优化:图片压缩、WebP/AVIF格式、字体子集化、懒加载图片/视频。
3. Vite vs Webpack?
大白话回答:
- Webpack:基于打包构建,开发时要全量打包,启动慢,热更新慢。
- Vite:基于ES Modules,开发时不打包,按需加载,启动极快,热更新快;生产用Rollup打包,体积更小。
七、手写题(必考,至少2道)
1. 实现Promise(基础版)
classMyPromise{constructor(executor){this.status='pending';this.value=undefined;this.reason=undefined;this.onFulfilledCallbacks=[];this.onRejectedCallbacks=[];constresolve=(value)=>{if(this.status==='pending'){this.status='fulfilled';this.value=value;this.onFulfilledCallbacks.forEach(fn=>fn());}};constreject=(reason)=>{if(this.status==='pending'){this.status='rejected';this.reason=reason;this.onRejectedCallbacks.forEach(fn=>fn());}};try{executor(resolve,reject);}catch(err){reject(err);}}then(onFulfilled,onRejected){returnnewMyPromise((resolve,reject)=>{if(this.status==='fulfilled'){setTimeout(()=>{try{constres=onFulfilled(this.value);resolve(res);}catch(err){reject(err);}});}if(this.status==='rejected'){setTimeout(()=>{try{constres=onRejected(this.reason);resolve(res);}catch(err){reject(err);}});}if(this.status==='pending'){this.onFulfilledCallbacks.push(()=>{setTimeout(()=>{try{constres=onFulfilled(this.value);resolve(res);}catch(err){reject(err);}});});this.onRejectedCallbacks.push(()=>{setTimeout(()=>{try{constres=onRejected(this.reason);resolve(res);}catch(err){reject(err);}});});}});}}2. 实现call/apply/bind
// callFunction.prototype.myCall=function(context,...args){context=context||window;constfn=Symbol();context[fn]=this;constresult=context[fn](...args);deletecontext[fn];returnresult;};// applyFunction.prototype.myApply=function(context,args){context=context||window;constfn=Symbol();context[fn]=this;constresult=args?context[fn](...args):context[fn]();deletecontext[fn];returnresult;};// bindFunction.prototype.myBind=function(context,...args){const_this=this;returnfunctionF(...newArgs){if(thisinstanceofF)returnnew_this(...args,...newArgs);return_this.apply(context,[...args,...newArgs]);};};3. 实现数组去重/扁平化/深拷贝(前面已写,略)
八、项目+场景题(必问,占比15%)
1. 项目难点怎么说?(万能模板)
大白话回答:
- 先讲业务背景:做了什么项目,解决什么问题。
- 再讲难点:比如“十万级表格渲染卡顿”“复杂表单联动”“跨端适配”。
- 然后讲解决方案:用了什么技术(虚拟列表、防抖、组件拆分、缓存)。
- 最后讲成果:性能提升多少(比如卡顿消失、加载速度快50%)、用户体验变好。
2. 如何处理大量数据渲染(比如10万条列表)?
大白话回答:
- 虚拟列表:只渲染可视区域的DOM,滚动时动态替换,减少DOM数量。
- 分页加载:后端分页,前端每次只加载一页。
- 懒加载+无限滚动:滚动到底部加载下一页。
- 数据缓存:用localStorage/Redux缓存已加载数据,避免重复请求。
- Web Worker:把数据处理放Worker,不阻塞主线程。
3. 如何做移动端适配?
大白话回答:
- rem适配:用
postcss-pxtorem,把px转rem,根字体大小随屏幕宽度变。 - vw/vh适配:1vw=1%视口宽度,直接用vw写样式,更简单。
- flex/grid布局:弹性布局,适配不同屏幕。
- 媒体查询:针对不同屏幕尺寸写样式。
九、面试必杀技巧(必看)
- 基础题要稳:HTML/CSS/JS基础是根本,必须滚瓜烂熟,别答非所问。
- 原理题要深:别只背概念,要讲清“是什么、为什么、怎么用、优缺点”。
- 手写题要快:高频手写题(Promise、防抖节流、call/apply/bind)提前练熟,面试直接写。
- 项目题要实:讲项目时突出技术亮点、解决的问题、量化成果(比如“优化后加载时间从3s降到1s”)。
- 不会别瞎编:诚实说“这个知识点我不太熟,回去会补”,比瞎编强。
- 反问环节:问“团队技术栈”“项目迭代节奏”“新人培养机制”,显诚意。
需要我把这份面试题整理成一份可直接背诵的精简版速记清单,方便你考前快速复习吗?
