前端面试主要围绕 HTML/CSS 基础、JavaScript 核心、DOM/BOM、框架原理(Vue/React)、性能优化、浏览器机制、网络知识 等核心领域展开。以下是分类整理的高频面试题及解析,帮助你系统备考。
一、HTML 基础

1. 什么是 HTML 语义化?有什么作用?
定义:语义化是指使用恰当的 HTML 标签(如 <header>、<nav>、<article>)描述内容的含义,而非仅通过 <div> + 类名。
作用:
提升可读性和可维护性(开发者更易理解结构)。
帮助搜索引擎优化(SEO,爬虫更易解析内容)。
增强 accessibility(无障碍,屏幕阅读器可正确识别内容)。
2. HTML5 新增了哪些特性?
语义化标签:<header>、<footer>、<section>、<article>、<nav> 等。
媒体标签:<video>、<audio> 原生支持音视频播放。
表单增强:新输入类型(type="email"、number、date)、表单验证属性(required、pattern)。
API 扩展:
本地存储(localStorage、sessionStorage)。
地理定位(Geolocation API)。
画布(<canvas> 用于绘图)。
拖放(Drag & Drop API)。
其他:DOCTYPE 简化(<!DOCTYPE html>)、废除过时标签(如 <font>、<center>)。
3. DOCTYPE 的作用是什么?
DOCTYPE(文档类型声明)位于 HTML 文档最顶部,用于 告诉浏览器当前文档使用的 HTML 版本规范,确保浏览器以正确的模式解析页面。
若缺失 DOCTYPE,浏览器会进入 “怪异模式(Quirks Mode)”,可能导致样式渲染不一致(如盒模型计算差异)。
4. meta 标签有哪些常用属性及作用?
charset="UTF-8":指定文档字符编码,避免中文乱码。
name="viewport":适配移动端,常用配置:
html
预览
<metaname="viewport"content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
作用:设置页面宽度为设备宽度,初始缩放比例 1:1,禁止用户缩放(优化移动端体验)。
name="description"/name="keywords":提供页面描述和关键词,辅助 SEO。
二、CSS 基础与进阶
1. CSS 选择器的优先级如何计算?
优先级从高到低为:
内联样式(style 属性,权重 1000)。
ID 选择器(#id,权重 100)。
类选择器(.class)、属性选择器([type="text"])、伪类(:hover)(权重 10)。
元素选择器(div)、伪元素(::before)(权重 1)。
规则:优先级高的样式覆盖低的;优先级相同则后定义的生效;!important 可强制提升优先级(不推荐滥用)。
2. 什么是 CSS 盒模型?标准盒模型与 IE 盒模型的区别?
定义:盒模型是 CSS 布局的基础,每个元素都被视为一个 “盒子”,包含 内容(content)、内边距(padding)、边框(border)、外边距(margin)。
区别:
标准盒模型(默认,box-sizing: content-box):
总宽度 = content-width + padding + border。
IE 盒模型(box-sizing: border-box):
总宽度 = width(包含 content + padding + border),更直观易控(常用于响应式布局)。
3. 如何实现元素的垂直居中?
根据场景不同,常见方案:
单行文本 / 内联元素:line-height: 父元素高度。
块级元素(已知高度):
绝对定位:position: absolute; top: 50%; margin-top: -高度/2;
块级元素(未知高度):
绝对定位 + transform:position: absolute; top: 50%; transform: translateY(-50%);
Flexbox:父元素 display: flex; align-items: center;(推荐,简单灵活)。
Grid:父元素 display: grid; place-items: center;(现代布局方案)。
4. Flexbox 布局的核心概念及常用属性?
核心概念:通过给父容器设置 display: flex,使其成为 “弹性容器”,子元素为 “弹性项”,通过主轴(默认水平)和交叉轴(默认垂直)控制布局。
容器常用属性:
flex-direction:主轴方向(row/column)。
justify-content:主轴对齐方式(flex-start/center/space-between)。
align-items:交叉轴对齐方式(flex-start/center/stretch)。
flex-wrap:弹性项是否换行(nowrap/wrap)。
项目常用属性:
flex: 1:简写(flex-grow 扩张比例 + flex-shrink 收缩比例 + flex-basis 基准尺寸),实现自适应布局。
align-self:单独设置项目的交叉轴对齐方式。
5. 什么是 BFC?如何触发 BFC?作用是什么?
定义:BFC(Block Formatting Context,块级格式化上下文)是一个独立的渲染区域,内部元素的布局不受外部影响,反之亦然。
触发条件(满足其一即可):
根元素(<html>)。
浮动元素(float: left/right)。
绝对 / 固定定位元素(position: absolute/fixed)。
overflow: hidden/auto/scroll(非 visible)。
弹性容器(display: flex/grid)。
作用:
解决浮动元素导致的父元素高度塌陷。
阻止元素被浮动元素覆盖。
隔离不同 BFC 区域,避免 margin 重叠。
6. CSS 中 position 的取值及区别?
取值含义应用场景
static默认值,元素遵循正常文档流,top/left 等属性无效。普通布局
relative相对自身原位置偏移,不脱离文档流,保留原占位。微调元素位置、作为绝对定位的父容器
absolute绝对定位,相对于最近的非 static 定位祖先元素偏移,脱离文档流。弹窗、导航菜单
fixed固定定位,相对于浏览器视口偏移,脱离文档流,滚动时位置不变。顶部导航栏、回到顶部按钮
sticky粘性定位,滚动到阈值前为 relative,之后为 fixed(如吸顶效果)。列表标题吸顶
三、JavaScript 核心
1. 基本数据类型与引用数据类型的区别?
基本数据类型:String、Number、Boolean、Null、Undefined、Symbol(ES6)、BigInt(ES11)。
特点:存储在栈内存,值不可变,赋值时直接拷贝值。
引用数据类型:Object(包括 Array、Function、Date 等)。
特点:存储在堆内存,栈内存仅存地址(引用),赋值时拷贝引用(指向同一对象),修改会影响原对象。
检测方式:
typeof:可检测基本类型(除 null 会返回 object),引用类型除 function 均返回 object。
instanceof:检测引用类型的具体类型(基于原型链)。
Object.prototype.toString.call():最准确,返回 [object 类型](如 [object Array])。
2. 什么是原型和原型链?
原型(prototype):每个函数(类)都有 prototype 属性,指向一个对象(原型对象),用于存储实例共享的方法和属性。
隐式原型(proto):每个对象都有 __proto__ 属性,指向其构造函数的 prototype(如 arr.__proto__ === Array.prototype)。
原型链:当访问对象的属性 / 方法时,若自身不存在,会通过 __proto__ 向上查找原型对象,直至 Object.prototype(顶端为 null),这种链式查找机制即原型链。
作用:实现继承和属性共享,减少内存消耗。
3. 什么是闭包?闭包的作用及可能引发的问题?
定义:函数嵌套时,内部函数引用外部函数的变量 / 参数,且内部函数被外部访问,导致外部函数的变量不会被垃圾回收,这种组合称为闭包。
javascript
运行
functionouter(){letcount=0;returnfunctioninner(){// 闭包 count++;returncount;};}constfn=outer();fn();// 1
作用:
封装私有变量(模块化)。
延长变量生命周期(如防抖节流中的定时器)。
问题:变量长期驻留内存,可能导致内存泄漏(需及时释放引用,如 fn = null)。
4. this 指向的规则?
this 指向在函数调用时确定,而非定义时:
全局环境:this 指向全局对象(浏览器为 window,Node 为 global)。
函数调用:fn() → this 指向全局对象(严格模式下为 undefined)。
对象方法调用:obj.fn() → this 指向调用者 obj。
构造函数调用:new Fn() → this 指向新创建的实例对象。
apply/call/bind:手动指定 this 指向(如 fn.call(obj) → this 指向 obj)。
箭头函数:无自己的 this,继承外层作用域的 this(固定不变,无法通过 call 等修改)。
5. 异步编程方案及演进?
回调函数:最早方案,易产生 “回调地狱”(嵌套过深)。
Promise:ES6 引入,通过 then() 链式调用解决回调地狱,三种状态:pending(进行中)、fulfilled(成功)、rejected(失败),状态一旦改变不可逆转。
javascript
运行
newPromise((resolve,reject)=>{setTimeout(()=>resolve("成功"),1000);}).then(res=>console.log(res)).catch(err=>console.log(err));
async/await:ES7 语法糖,基于 Promise,用同步代码风格写异步,更简洁易读。
javascript
运行
asyncfunctionfn(){try{constres=awaitnewPromise(resolve=>resolve("成功"));console.log(res);}catch(err){console.log(err);}}
6. 事件循环(Event Loop)的原理?
JavaScript 是单线程,通过事件循环实现非阻塞异步:
执行栈:同步任务按顺序执行,执行完后处理异步任务。
任务队列:异步任务(如 setTimeout、Promise.then、DOM 事件)完成后,回调函数放入队列。
微任务(Microtasks) vs 宏任务(Macrotasks):
微任务优先级更高,包括:Promise.then/catch/finally、process.nextTick(Node)、queueMicrotask。
宏任务包括:setTimeout、setInterval、DOM 事件、fetch、script 整体代码。
流程:
执行同步代码(执行栈清空)。
执行所有微任务(清空微任务队列)。
执行一个宏任务,然后重复步骤 2(循环)。
7. ES6+ 有哪些常用新特性?
变量声明:let(块级作用域,不可重复声明)、const(声明常量,值不可改)。
箭头函数:(a, b) => a + b,简化语法,无自己的 this。
解构赋值:const { name } = obj; const [a, b] = arr,快速提取对象 / 数组属性。
模板字符串:`Hello ${name}`,支持换行和变量嵌入。
类与继承:class 语法糖,extends 实现继承(基于原型)。
模块化:import/export 替代 CommonJS,支持静态导入。
其他:Set/Map 数据结构、Promise、async/await、扩展运算符(...)、默认参数(function fn(a=1) {})。
四、DOM 与 BOM
1. 如何操作 DOM?常用 API 有哪些?
创建节点:document.createElement(tagName)、document.createTextNode(text)。
添加节点:parent.appendChild(child)、parent.insertBefore(newNode, referenceNode)。
删除节点:parent.removeChild(child)。
修改节点:element.textContent = "内容"、element.innerHTML = "<div>HTML</div>"。
查询节点:
document.getElementById(id)、document.getElementsByClassName(class)。
document.querySelector(selector)(返回第一个匹配元素)、document.querySelectorAll(selector)(返回 NodeList)。
2. 事件冒泡与事件捕获的区别?如何阻止?
事件捕获:事件从最外层祖先元素向目标元素传播(“从上到下”)。
事件冒泡:事件从目标元素向最外层祖先元素传播(“从下到上”,默认触发)。
阻止方式:
阻止冒泡:event.stopPropagation()。
阻止默认行为(如表单提交、链接跳转):event.preventDefault()。
3. 什么是事件委托?有什么优势?
定义:将子元素的事件监听委托给父元素,利用事件冒泡触发父元素的事件处理函数,再通过 event.target 判断具体触发的子元素。
javascript
运行
// 为 ul 委托监听 li 的点击事件 document.querySelector('ul').addEventListener('click',(e)=>{if(e.target.tagName==='LI'){console.log('点击了 li');}});
优势:
减少事件监听数量,优化性能(尤其子元素动态生成时)。
动态新增的子元素自动继承事件监听,无需重新绑定。
4. 本地存储方案及区别(Cookie、localStorage、sessionStorage)?
特性CookielocalStoragesessionStorage
存储大小约 4KB约 5MB约 5MB
有效期可设置过期时间(expires)永久有效(除非手动删除)会话级(页面关闭后清除)
通信每次请求自动携带(HTTP 头部)不参与网络传输不参与网络传输
作用域同源且符合路径规则同源页面共享仅当前标签页 / 窗口
API 复杂度需手动封装(document.cookie)简洁(setItem/getItem)同 localStorage
五、前端框架(以 Vue 和 React 为例)
Vue 核心问题
1. Vue 的响应式原理是什么?
Vue 2 基于 Object.defineProperty 实现:
初始化时,对 data 中的属性递归遍历,通过 Object.defineProperty 为属性添加 getter 和 setter。
getter 触发时收集依赖(Watcher),setter 触发时通知依赖更新(重新渲染)。
缺陷:无法监听对象新增属性、数组索引 / 长度变化(需用 Vue.set 或 this.$set 手动触发更新)。
Vue 3 改用 Proxy 实现:
直接代理整个对象(而非属性),支持监听对象新增属性、数组变化,无需手动处理,性能更优。
2. Vue 组件的生命周期钩子有哪些?常用场景?
创建阶段:
beforeCreate:实例初始化后,数据和方法未挂载,无法访问 data/methods。
created:数据和方法已挂载,可访问数据,但 DOM 未生成(常用于初始化数据、发请求)。
挂载阶段:
beforeMount:模板编译完成,未挂载到 DOM。
mounted:DOM 已挂载,可操作 DOM(常用于初始化插件、图表)。
更新阶段:
beforeUpdate:数据更新后,DOM 未更新前触发。
updated:DOM 已更新,可获取最新 DOM 状态。
销毁阶段:
beforeDestroy:实例销毁前,可清理定时器、解绑事件。
destroyed:实例已销毁,所有监听和子组件被移除。
3. Vue 组件通信方式有哪些?
父子组件:
父传子:props 传递数据,子组件通过 props 接收。
子传父:子组件 $emit('事件名', 数据),父组件 @事件名 监听。
跨级 / 兄弟组件:
Vuex/Pinia:全局状态管理(推荐)。
provide/inject:祖先组件 provide 提供数据,后代组件 inject 注入(非响应式,适合深层传递)。
事件总线(EventBus):通过 new Vue() 创建总线,$on 监听、$emit 触发(小型项目)。
React 核心问题
1. React 的虚拟 DOM(Virtual DOM)是什么?作用?
定义:虚拟 DOM 是内存中的 JavaScript 对象,映射真实 DOM 的结构(如 { tag: 'div', props: {}, children: [] })。
作用:
减少真实 DOM 操作:React 先对比新旧虚拟 DOM 的差异(Diff 算法),仅更新变化的部分到真实 DOM,降低性能损耗。
跨平台:虚拟 DOM 可渲染到不同平台(如 React Native 渲染到原生组件)。
2. React Hooks 是什么?常用 Hooks 及作用?
Hooks 是 React 16.8 新增特性,允许函数组件使用状态和生命周期等特性,无需编写类组件。
useState:为函数组件添加状态。
javascript
运行
const[count,setCount]=useState(0);// 初始值 0
useEffect:处理副作用(如请求、定时器、事件监听),替代类组件的生命周期。
javascript
运行
// 相当于 componentDidMount + componentDidUpdate useEffect(()=>{consttimer=setInterval(()=>setCount(c=>c+1),1000);// 清理函数(相当于 componentWillUnmount) return()=>clearInterval(timer);},[]);// 空依赖数组:仅执行一次
其他常用 Hooks:useContext(共享状态)、useReducer(复杂状态管理)、useRef(获取 DOM 或保存变量)。
六、性能优化
1. 页面加载性能优化有哪些方法?
资源优化:
压缩资源(JS/CSS 压缩,图片压缩 / 格式优化如 WebP)。
代码分割(按需加载,如路由懒加载 React.lazy/Vue 路由懒加载)。
利用 CDN 分发静态资源(减少网络延迟)。
加载策略:
懒加载(图片、组件:loading="lazy" 或 IntersectionObserver)。
预加载(link rel="preload" 提前加载关键资源)。
减少 HTTP 请求(合并 JS/CSS,使用雪碧图)。
缓存优化:
强缓存(Cache-Control: max-age=31536000)和协商缓存(ETag/Last-Modified)。
2. 渲染性能优化有哪些方法?
减少重排(Reflow)和重绘(Repaint):
重排:DOM 布局变化(如尺寸、位置改变),开销大;重绘:样式变化(如颜色),开销较小。
优化:批量修改 DOM(离线操作 documentFragment)、避免频繁读取布局属性(如 offsetHeight)、使用 transform/opacity(触发合成层,无重排)。
JavaScript 优化:
防抖(debounce):避免高频事件(如 resize)多次触发(如搜索输入联想)。
节流(throttle):限制事件触发频率(如滚动加载)。
避免长任务阻塞主线程(用 Web Worker 处理复杂计算)。
七、浏览器与网络
1. 浏览器的渲染流程是什么?
解析 HTML:生成 DOM 树(Document Object Model)。
解析 CSS:生成 CSSOM 树(CSS Object Model)。
构建渲染树(Render Tree):结合 DOM 树和 CSSOM 树,过滤不可见元素(如 display: none)。
布局(Layout):计算渲染树中元素的位置和尺寸(重排发生在此阶段)。
绘制(Paint):将元素绘制到屏幕(重绘发生在此阶段)。
合成(Composite):将绘制的图层合并,显示到屏幕(如 z-index 层级处理)。
2. 跨域问题的原因及解决方案?
原因:浏览器的同源策略限制(协议、域名、端口三者必须相同),禁止跨域请求资源。
解决方案:
CORS(跨域资源共享):服务器端设置响应头 Access-Control-Allow-Origin: *(或指定域名),支持所有 HTTP 方法。
JSONP:利用 <script> 标签不受同源限制,动态创建 script 发送请求,服务器返回回调函数包裹数据(仅支持 GET)。
代理服务器:开发环境用 Webpack Dev Server 代理,生产环境用 Nginx 反向代理,将跨域请求转为同域请求。
八、手写题(高频)
1. 手写防抖(Debounce)
javascript
运行
// 触发后延迟 wait 毫秒执行,若期间再次触发则重置计时 functiondebounce(fn,wait){lettimer=null;returnfunction(...args){clearTimeout(timer);timer=setTimeout(()=>{fn.apply(this,args);},wait);};}
2. 手写节流(Throttle)
javascript
运行
// 每隔 wait 毫秒最多执行一次 functionthrottle(fn,wait){letlastTime=0;returnfunction(...args){constnow=Date.now();if(now-lastTime>=wait){fn.apply(this,args);lastTime=now;}};}
3. 手写深拷贝(考虑对象、数组、函数)
javascript
运行
functiondeepClone(obj,hash=newWeakMap()){if(obj===null||typeofobj!=='object')returnobj;// 非对象直接返回 if(hash.has(obj))returnhash.get(obj);// 处理循环引用 letcloneObj;// 区分数组和对象 if(objinstanceofArray){cloneObj=[];}elseif(objinstanceofObject){cloneObj={};}hash.set(obj,cloneObj);// 缓存已拷贝对象 // 递归拷贝属性 Reflect.ownKeys(obj).forEach(key=>{cloneObj[key]=deepClone(obj[key],hash);});returncloneObj;}