前端知识点全解析
作为一名前端高级开发人员,面试不仅考察知识点的记忆,更关注对原理的理解、工程化的思考以及解决复杂问题的能力。本文将从 HTML/CSS、JavaScript、浏览器与网络、框架、工程化、性能优化、算法与设计模式等多个维度,系统梳理前端面试中的核心知识点,并提供深入解析及案例,帮助你在面试中展现出真正的技术深度。
1. HTML & CSS 基础
1.1 语义化 HTML
讲解:语义化 HTML 是指使用具有明确含义的标签(如 <header>、<nav>、<article>、<section>)来描述网页结构,而不是单纯使用 <div> 和 <span>。
解析:
- SEO 友好:搜索引擎爬虫依赖语义标签理解页面内容,有助于提升排名。
- 可访问性:屏幕阅读器等辅助技术可以更好地解析页面,为视障用户提供良好体验。
- 代码可维护性:团队协作时,语义化标签让代码结构清晰易懂。
- 常见语义标签:
<header>、<footer>、<main>、<aside>、<article>、<section>、<nav>。
案例:
<!-- 非语义化 --><divclass="header"><divclass="logo">MySite</div><divclass="nav"><ahref="/">首页</a><ahref="/about">关于</a></div></div><!-- 语义化 --><header><h1class="logo">MySite</h1><nav><ul><li><ahref="/">首页</a></li><li><ahref="/about">关于</a></li></ul></nav></header>面试题:<b> 和 <strong> 的区别?
解析:<b> 仅表示粗体样式,无语义;<strong> 表示强调内容,有语义,屏幕阅读器会以重音读出。
1.2 盒模型
讲解:CSS 盒模型描述了一个元素所占空间的结构,包括内容(content)、内边距(padding)、边框(border)、外边距(margin)。
解析:
- 标准盒模型:
width/height只包含内容区,不包含 padding 和 border。总宽度 = width + padding + border + margin。 - IE 盒模型(怪异盒模型):
width/height包含内容、padding 和 border。总宽度 = width + margin。 - 切换方式:通过
box-sizing: content-box(默认)或box-sizing: border-box设置。 - 实际应用:通常将
box-sizing设置为border-box更易于布局,避免频繁计算宽高。
案例:
/* 标准盒模型 */.box-standard{box-sizing: content-box;width: 100px;padding: 10px;border: 5px solid black;margin: 10px;/* 实际占据宽度 = 100 + 10*2 + 5*2 = 130px */}/* IE盒模型(常用) */.box-border{box-sizing: border-box;width: 100px;padding: 10px;border: 5px solid black;margin: 10px;/* 实际占据宽度 = 100px(包含padding和border) */}1.3 布局方式
1.3.1 浮动与清除浮动
讲解:float 使元素脱离文档流,向左或向右浮动,常用于文字环绕图片或实现多列布局。
解析:
- 浮动影响:父容器高度塌陷(因为浮动元素不占文档流高度)。
- 清除浮动方法:
- 在父容器末尾添加空元素并设置
clear: both。 - 父容器触发 BFC(如
overflow: hidden)。 - 使用伪元素:
.clearfix::after { content: ""; display: table; clear: both; }。
- 在父容器末尾添加空元素并设置
案例:
<divclass="container clearfix"><divclass="float-left">浮动元素</div><divclass="float-left">浮动元素</div></div><style>.float-left{float: left;width: 100px;height: 100px;background: lightblue;}.clearfix::after{content:"";display: table;clear: both;}</style>1.3.2 定位
讲解:position 属性控制元素的定位方式,包括 static、relative、absolute、fixed、sticky。
解析:
relative:相对自身原本位置偏移,仍占文档流空间。absolute:相对最近的非static祖先元素定位,脱离文档流。fixed:相对视口定位,脱离文档流。sticky:粘性定位,根据滚动阈值在relative和fixed之间切换。- 层叠上下文:
z-index仅在非static定位元素上生效,且受层叠上下文影响。
案例:
<divclass="parent"style="position: relative;height: 200px;background: #eee;"><divclass="child"style="position: absolute;bottom: 10px;right: 10px;">绝对定位</div></div><divclass="sticky"style="position: sticky;top: 0;">粘性头部</div>1.3.3 Flex 布局
讲解:Flex 是一维布局模型,提供强大的对齐和空间分配能力。
解析:
- 容器属性:
display: flex;flex-direction(主轴方向);justify-content(主轴对齐);align-items(交叉轴对齐);flex-wrap(换行)。 - 项目属性:
flex-grow(放大比例)、flex-shrink(缩小比例)、flex-basis(初始大小);align-self(覆盖容器的align-items)。 - 经典应用:垂直居中(
justify-content: center; align-items: center)、圣杯布局、等分布局。
案例:
.container{display: flex;justify-content: space-between;align-items: center;height: 200px;}.item{flex: 1;/* 等分剩余空间 */margin: 10px;}1.3.4 Grid 布局
讲解:Grid 是二维布局模型,将容器划分为行和列,可精确控制元素位置。
解析:
- 容器属性:
display: grid;grid-template-rows/columns定义行/列轨道;gap间隙;justify/align-items控制单元格内对齐。 - 项目属性:
grid-row/column指定项目占据的网格线;justify/align-self控制项目自身对齐。 - 与 Flex 区别:Grid 适合整体页面布局,Flex 适合组件内部的一维排列。
案例:
.grid-container{display: grid;grid-template-columns: 1fr 2fr 1fr;grid-template-rows: 100px 200px;gap: 10px;}.item{background: lightcoral;}.item:first-child{grid-column: 1 / 3;/* 跨两列 */}1.4 响应式设计
讲解:响应式设计使网站在不同设备(手机、平板、桌面)上都能良好显示。
解析:
- 视口(viewport):通过
<meta name="viewport" content="width=device-width, initial-scale=1">设置,确保页面宽度适配设备宽度。 - 媒体查询:
@media (max-width: 768px) { ... }根据屏幕尺寸应用不同样式。 - 相对单位:
em(相对于父元素字体)、rem(相对于根元素字体)、vw/vh(视口宽高百分比)、%。 - 弹性布局:结合 Flex/Grid 实现容器自适应。
- 图片响应式:
srcset和sizes属性或<picture>元素,根据分辨率加载合适图片。
案例:
<imgsrcset="small.jpg 300w, medium.jpg 600w, large.jpg 900w"sizes="(max-width: 600px) 100vw, (max-width: 900px) 50vw, 33vw"src="large.jpg"alt="响应式图片"><style>.container{width: 80%;margin: 0 auto;}@media(max-width: 768px){.container{width: 100%;padding: 0 10px;}}</style>1.5 CSS 预处理器
讲解:Sass、Less 等预处理器为 CSS 提供了变量、嵌套、混合、继承等编程特性。
解析:
- 变量:
$primary-color(Sass)或@primary-color(Less),便于主题管理。 - 嵌套:减少重复父选择器,但避免过深嵌套。
- 混合(mixin):可复用样式块,可传参。
- 函数与运算:颜色函数、数学运算。
- 模块化:
@import分割文件,最终编译为一个 CSS 文件。
案例(Sass):
$primary: #007bff; $spacing: 1rem; @mixin rounded($radius: 4px) { border-radius: $radius; } .button { background: $primary; padding: $spacing/2 $spacing; @include rounded(8px); &:hover { background: darken($primary, 10%); } } 1.6 BEM 命名规范
讲解:BEM(Block Element Modifier)是一种 CSS 命名方法论,旨在提高代码可读性和可维护性。
解析:
- Block:独立实体,如
.header、.menu。 - Element:属于块的一部分,如
.header__logo、.menu__item。 - Modifier:修饰块或元素的状态,如
.header--fixed、.menu__item--active。 - 优点:避免样式冲突,清晰的结构关系。
案例:
<divclass="card"><divclass="card__header"><h2class="card__title">标题</h2></div><divclass="card__body">内容</div><divclass="card__footer card__footer--highlighted">底部高亮</div></div><style>.card__footer--highlighted{background: yellow;}</style>1.7 层叠上下文与 z-index
讲解:层叠上下文是 HTML 元素在 Z 轴上的层级概念,z-index 决定同一层叠上下文中元素的堆叠顺序。
解析:
- 创建层叠上下文的条件:根元素、
position非static且z-index值不为auto、opacity小于 1、transform非none、filter非none等。 - z-index 比较:只有同一层叠上下文内的元素才能比较
z-index;不同上下文中,父级上下文决定层级。 - 常见问题:明明设置了很大的
z-index却无效,通常是因为元素不在同一个层叠上下文,或父级z-index限制。
案例:
<divstyle="position: relative;z-index: 1;"><divstyle="position: absolute;z-index: 999;">这个999受父级1限制</div></div><divstyle="position: relative;z-index: 2;"><divstyle="position: absolute;z-index: 1;">这个1比上面的999大,因为父级z-index=2更高</div></div>2. JavaScript 核心
2.1 数据类型与类型判断
讲解:JavaScript 有 8 种数据类型:undefined、null、boolean、number、string、symbol(ES6)、bigint(ES11)、object。其中前 7 种为原始类型,object 为引用类型。
解析:
- 类型判断方法:
typeof:适合原始类型,但typeof null === 'object'(历史遗留 bug),typeof function(){} === 'function'。instanceof:检查对象原型链,用于判断引用类型。Object.prototype.toString.call():最准确,返回[object Type]。
- 隐式类型转换:
+、==等操作符会触发类型转换,需注意规则(如[] == ![]结果为 true)。
案例:
console.log(typeof42);// "number" console.log(typeof'hello');// "string" console.log(typeoftrue);// "boolean" console.log(typeofundefined);// "undefined" console.log(typeofnull);// "object" (历史遗留) console.log(typeof{});// "object" console.log(typeoffunction(){});// "function" console.log([]instanceofArray);// true console.log({}instanceofObject);// true console.log(Object.prototype.toString.call([]));// "[object Array]" console.log(Object.prototype.toString.call(null));// "[object Null]"2.2 作用域与闭包
讲解:作用域决定了变量的可访问范围。JavaScript 采用词法作用域(静态作用域),函数的作用域在定义时确定。闭包是指有权访问另一个函数作用域中变量的函数。
解析:
- 作用域链:当访问变量时,从当前作用域开始向上查找,直到全局。
- 闭包的形成:内部函数引用了外部函数的变量,即使外部函数执行完毕,变量仍被内部函数引用,不会被垃圾回收。
- 常见用途:
- 封装私有变量(模块模式)。
- 函数柯里化。
- 循环中使用
var创建多个闭包(通常用 IIFE 或let解决)。
- 内存泄漏:闭包不当会导致内存无法释放,应避免无限制使用。
案例:
// 闭包封装私有变量functioncreateCounter(){let count =0;return{increment:()=>++count,decrement:()=>--count,getCount:()=> count };}const counter =createCounter(); console.log(counter.increment());// 1 console.log(counter.increment());// 2 console.log(counter.getCount());// 22.3 原型与原型链
讲解:JavaScript 通过原型实现继承。每个对象都有一个 __proto__ 属性指向其构造函数的原型对象 prototype。原型链由多个对象的 __proto__ 链接而成。
解析:
- 构造函数:函数本身也是对象,拥有
prototype属性。通过new调用构造函数创建实例,实例的__proto__指向构造函数的prototype。 - 原型链查找:访问对象属性时,如果对象自身没有,则沿着
__proto__向上查找,直到null。 - 原型链终点:
Object.prototype.__proto__ === null。 - 继承方式:
- 原型链继承:
Child.prototype = new Parent()。 - 组合继承:原型链 + 构造函数。
- ES6
class语法糖(本质仍是原型链)。
- 原型链继承:
instanceof原理:检测右侧构造函数的prototype是否在左侧对象的原型链上。
案例:
functionAnimal(name){this.name = name;}Animal.prototype.speak=function(){ console.log(`${this.name} makes a sound.`);};functionDog(name, breed){Animal.call(this, name);// 借用构造函数this.breed = breed;}// 原型链继承Dog.prototype = Object.create(Animal.prototype);Dog.prototype.constructor = Dog;Dog.prototype.bark=function(){ console.log(`${this.name} barks.`);};const d =newDog('Rex','Husky'); d.speak();// Rex makes a sound. d.bark();// Rex barks. console.log(d instanceofDog);// true console.log(d instanceofAnimal);// true2.4 this 指向与 call/apply/bind
讲解:this 的值在函数调用时确定,取决于调用方式。
解析:
- 默认绑定:独立函数调用,
this指向全局对象(浏览器中为window),严格模式为undefined。 - 隐式绑定:作为对象方法调用,
this指向该对象。 - 显式绑定:
call、apply、bind可以强制指定this。call(thisArg, arg1, arg2...):立即执行,参数列表。apply(thisArg, [arg1, arg2...]):立即执行,参数数组。bind(thisArg, arg1, arg2...):返回新函数,永久绑定this。
- new 绑定:使用
new调用构造函数,this指向新创建的对象。 - 箭头函数:没有自己的
this,捕获外层作用域的this(词法绑定)。 - 优先级:
new> 显式绑定 > 隐式绑定 > 默认绑定。
案例:
functiongreet(greeting, punctuation){ console.log(greeting +', '+this.name + punctuation);}const person ={name:'Alice'};greet.call(person,'Hello','!');// Hello, Alice!greet.apply(person,['Hi','?']);// Hi, Alice?const bound =greet.bind(person,'Hey');bound('!!');// Hey, Alice!!2.5 异步编程
2.5.1 回调函数
讲解:将函数作为参数传入,在异步操作完成后调用。
解析:
- 优点:简单直观。
- 缺点:回调地狱(多层嵌套)、错误处理困难、代码可读性差。
案例:
functionfetchData(callback){setTimeout(()=>{callback('data');},1000);}fetchData((result)=>{ console.log(result);});2.5.2 Promise
讲解:Promise 是异步编程的解决方案,代表一个最终完成或失败的操作。
解析:
- 状态:
pending(进行中)、fulfilled(已成功)、rejected(已失败)。状态一旦改变不可逆。 - 实例方法:
then(onFulfilled, onRejected):返回新 Promise,支持链式调用。catch(onRejected):相当于.then(null, onRejected)。finally(onFinally):无论成功失败都会执行。
- 静态方法:
Promise.all(iterable):全部成功才成功,任一失败则立即失败。Promise.race(iterable):首个状态变更的 Promise 决定结果。Promise.allSettled(iterable):等待所有完成,返回每个结果(fulfilled/rejected)。Promise.any(iterable):首个成功的结果,若全部失败则 AggregateError。
- 错误处理:Promise 链中通过
catch捕获错误,注意在then中抛出的错误也会被后续catch捕获。
案例:
functionasyncTask(shouldResolve){returnnewPromise((resolve, reject)=>{setTimeout(()=>{ shouldResolve ?resolve('成功'):reject('失败');},1000);});}asyncTask(true).then(result=> console.log(result)).catch(error=> console.error(error)); Promise.all([asyncTask(true),asyncTask(true)]).then(results=> console.log('全部成功', results)).catch(err=> console.error('至少一个失败', err));2.5.3 async/await
讲解:async/await 是 ES2017 引入的语法糖,基于 Promise,使异步代码像同步一样书写。
解析:
- async 函数:返回一个 Promise,内部返回值会被
Promise.resolve()包装。 - await 表达式:等待一个 Promise 完成,会暂停当前 async 函数的执行,直到 Promise 状态变为 fulfilled 或 rejected。
- 错误处理:使用
try/catch捕获 await 中 Promise 的 reject。 - 注意事项:await 只能在 async 函数中使用;多个无依赖的异步操作应使用
Promise.all并发执行,避免串行等待。
案例:
asyncfunctionfetchData(){try{const result =awaitasyncTask(true); console.log(result);const data =awaitasyncTask(true); console.log(data);}catch(error){ console.error('捕获错误:', error);}}fetchData();2.6 事件循环与宏任务/微任务
讲解:JavaScript 是单线程语言,通过事件循环机制处理异步任务。任务分为宏任务(macrotask)和微任务(microtask)。
解析:
- 宏任务:script 整体代码、
setTimeout、setInterval、I/O、UI 渲染等。 - 微任务:
Promise.then/catch/finally、MutationObserver、queueMicrotask、process.nextTick(Node)。 - 执行顺序:
- 执行当前宏任务(如 script 整体)。
- 执行所有微任务(清空微任务队列)。
- 取出下一个宏任务执行,重复。
经典题目:
console.log('1');setTimeout(()=> console.log('2'),0); Promise.resolve().then(()=> console.log('3')); console.log('4');// 输出顺序:1,4,3,2案例:
console.log('start');setTimeout(()=> console.log('timeout'),0); Promise.resolve().then(()=> console.log('promise1')); Promise.resolve().then(()=>{ console.log('promise2');setTimeout(()=> console.log('timeout inside promise'),0);}); console.log('end');// 输出:start, end, promise1, promise2, timeout, timeout inside promise2.7 深拷贝与浅拷贝
讲解:浅拷贝只复制对象的第一层属性,引用类型仍共享引用;深拷贝递归复制所有层级,生成独立对象。
解析:
- 浅拷贝方法:
Object.assign()、扩展运算符{...obj}、Array.prototype.slice()。 - 深拷贝方法:
JSON.parse(JSON.stringify(obj)):缺点是无法处理函数、undefined、Symbol、循环引用。- 递归实现(需处理各种数据类型)。
- 使用结构化克隆:
structuredClone()(现代浏览器支持)。 - 第三方库如 Lodash 的
_.cloneDeep。
- 性能考量:深拷贝成本高,应根据场景选择。
案例:
const original ={a:1,b:{c:2}};// 浅拷贝const shallow ={...original }; shallow.b.c =3; console.log(original.b.c);// 3 (相互影响)// 深拷贝const deep =JSON.parse(JSON.stringify(original)); deep.b.c =4; console.log(original.b.c);// 3 (独立)2.8 防抖与节流
讲解:防抖和节流是限制函数执行频率的优化手段。
解析:
- 区别:防抖是“延迟合并”,节流是“频率限制”。
节流(throttle):规定一个单位时间内,只能触发一次函数。适用于滚动加载、频繁点击。
functionthrottle(fn, interval){let lastTime =0;returnfunction(...args){const now = Date.now();if(now - lastTime >= interval){fn.apply(this, args); lastTime = now;}};}防抖(debounce):在事件被触发 n 秒后执行回调,如果在这 n 秒内又被触发,则重新计时。适用于输入框搜索、窗口 resize。
functiondebounce(fn, delay){let timer =null;returnfunction(...args){clearTimeout(timer); timer =setTimeout(()=>fn.apply(this, args), delay);};}案例:
<inputid="search"type="text"placeholder="搜索"><script>const input = document.getElementById('search'); input.addEventListener('input',debounce(function(e){ console.log('发送请求:', e.target.value);},500));</script>2.9 数组/对象常用方法
讲解:掌握 ES5/ES6 中数组和对象的常用方法。
解析:
- 数组方法:
- 迭代:
forEach、map、filter、reduce、some、every。 - 查找:
indexOf、find、findIndex、includes。 - 增删改:
push/pop、shift/unshift、splice、concat、slice。 - 排序/反转:
sort、reverse。 - 扁平化:
flat、flatMap。
- 迭代:
- 对象方法:
- 遍历:
Object.keys()、Object.values()、Object.entries()。 - 拷贝/合并:
Object.assign()。 - 创建:
Object.create()(指定原型)。 - 属性描述符:
Object.defineProperty()。
- 遍历:
案例:
// 数组const arr =[1,2,3,4];const doubled = arr.map(x=> x *2);// [2,4,6,8]const evens = arr.filter(x=> x %2===0);// [2,4]const sum = arr.reduce((acc, cur)=> acc + cur,0);// 10// 对象const obj ={a:1,b:2}; Object.keys(obj).forEach(key=> console.log(key, obj[key]));const merged = Object.assign({}, obj,{c:3});// {a:1,b:2,c:3}3. 浏览器与网络
3.1 浏览器渲染原理
讲解:浏览器从获取 HTML 到渲染出页面的过程。
解析:
- 解析 HTML:构建 DOM 树。
- 解析 CSS:构建 CSSOM 树。
- 合并:生成渲染树(Render Tree),只包含可见节点。
- 布局(Layout/Reflow):计算每个节点的几何位置。
- 绘制(Paint):将渲染树绘制到屏幕。
- 合成(Composite):分层绘制,利用 GPU 加速。
- 关键点:CSS 不会阻塞 DOM 解析,但会阻塞渲染;JS 会阻塞 DOM 解析(除非标记
async或defer)。
案例:
<!-- 模拟阻塞 --><scriptsrc="slow.js"></script><!-- 会阻塞后续DOM解析 --><scriptasyncsrc="async.js"></script><!-- 下载不阻塞,执行可能乱序 --><scriptdefersrc="defer.js"></script><!-- 下载不阻塞,在DOM解析完后执行 -->3.2 回流与重绘
讲解:回流(Reflow)指元素的几何属性(尺寸、位置)发生变化,需要重新计算布局;重绘(Repaint)指元素样式改变但不影响布局(如颜色、背景)。
解析:
- 触发回流的操作:添加/删除 DOM、修改元素尺寸、页面初始渲染、窗口大小变化、获取某些属性(如
offsetWidth)时可能强制同步布局。 - 优化策略:
- 批量修改样式(使用
class或cssText)。 - 将元素脱离文档流(
position: absolute)后再操作。 - 使用
requestAnimationFrame读写 DOM。 - 避免频繁读取布局属性。
- 批量修改样式(使用
案例:
// 避免多次触发回流const div = document.getElementById('box'); div.style.width ='100px';// 回流 div.style.height ='100px';// 再次回流// 优化:合并修改 div.style.cssText ='width: 100px; height: 100px;';// 或使用class div.classList.add('big-box');3.3 跨域解决方案
讲解:同源策略限制不同源(协议、域名、端口任一不同)的资源交互。跨域指突破此限制进行通信。
解析:
- JSONP:利用
<script>标签没有跨域限制,通过动态创建 script 加载带回调函数名的 URL。仅支持 GET。 - CORS(跨域资源共享):服务器设置响应头
Access-Control-Allow-Origin允许特定来源。支持所有 HTTP 方法。- 简单请求和非简单请求(需预检请求 OPTIONS)。
- 代理服务器:开发环境下配置 webpack-dev-server 的 proxy,或 Nginx 反向代理。
- postMessage:用于 iframe 或窗口间通信。
- WebSocket:不受同源策略限制。
- document.domain:适用于主域相同子域不同的情况(已过时)。
案例:
// JSONPfunctionjsonp(url, callbackName){const script = document.createElement('script'); script.src =`${url}?callback=${callbackName}`; window[callbackName]=(data)=>{ console.log('接收数据:', data);delete window[callbackName]; document.body.removeChild(script);}; document.body.appendChild(script);}jsonp('http://api.example.com/data','handleData');// CORS: 服务器设置响应头 Access-Control-Allow-Origin: *3.4 HTTP 协议
讲解:HTTP 是 Web 基础协议,经历了多个版本演进。
解析:
- HTTP/1.0:每个 TCP 连接只能发送一个请求,请求结束立即关闭,效率低。
- HTTP/1.1:
- 持久连接(keep-alive),允许多个请求复用同一个 TCP 连接。
- 管道化(pipelining),但队头阻塞问题仍存在(必须按顺序响应)。
- 增加了 Host 头、缓存控制(Cache-Control)等。
- HTTP/2.0:
- 二进制分帧层,将请求/响应分割为帧,实现多路复用(一个连接同时处理多个请求,解决队头阻塞)。
- 头部压缩(HPACK),减少开销。
- 服务器推送(server push)。
- HTTP/3.0:基于 QUIC 协议(UDP),解决 TCP 队头阻塞,更快建立连接。
案例:
// HTTP/2 服务器推送示例(需服务器支持)// 在响应头中推送关键资源Link:</styles.css>; rel=preload;as=style 3.5 缓存机制
讲解:浏览器缓存分为强缓存和协商缓存,减少网络请求,提高加载速度。
解析:
- 强缓存:
Expires:HTTP/1.0 头,绝对时间,依赖客户端时间。Cache-Control:HTTP/1.1 头,优先级高,常用值max-age=秒。
- 协商缓存:
Last-Modified/If-Modified-Since:资源最后修改时间,可能不准确(如文件修改但内容未变)。ETag/If-None-Match:资源唯一标识(哈希),更精确。
- 缓存位置:Service Worker、Memory Cache、Disk Cache、Push Cache。
- 缓存策略:HTML 通常协商缓存或禁用缓存;CSS/JS/图片设置强缓存,并配合文件名哈希更新。
案例:
<!-- 通过meta禁用缓存(不推荐,用HTTP头) --><metahttp-equiv="Cache-Control"content="no-cache, no-store, must-revalidate"/><!-- 服务器设置强缓存:Cache-Control: max-age=31536000 --><!-- 资源通过哈希更新:main.a1b2c3.js -->3.6 Web 安全
3.6.1 XSS(跨站脚本攻击)
讲解:攻击者注入恶意脚本到可信网站,当用户浏览时执行。
解析:
- 反射型:恶意脚本通过 URL 参数注入,后端未过滤直接返回。
- 存储型:恶意脚本存储在服务器数据库,如评论区,每次访问都触发。
- DOM 型:纯前端漏洞,通过修改 DOM 执行脚本。
- 防御:
- 输入过滤(对用户输入进行转义)。
- 输出编码(使用
textContent而不是innerHTML)。 - 设置
Content-Security-Policy(CSP)限制资源加载。 - 使用 HttpOnly Cookie 防止 Cookie 被脚本窃取。
案例:
// 防御:对用户输入进行转义functionescapeHTML(str){return str.replace(/[&<>"]/g,function(m){if(m ==='&')return'&';if(m ==='<')return'<';if(m ==='>')return'>';if(m ==='"')return'"';return m;});}const userComment ='<script>alert(1)</script>'; document.getElementById('comment').textContent =escapeHTML(userComment);3.6.2 CSRF(跨站请求伪造)
讲解:攻击者诱导用户访问第三方网站,利用用户的登录态向目标网站发起恶意请求。
解析:
- 防御:
- 使用 CSRF Token:表单中嵌入随机 token,服务端验证。
- SameSite Cookie 属性:设置为
Strict或Lax,限制跨站发送 Cookie。 - 验证 Referer 或 Origin 头。
- 使用验证码(重要操作)。
案例:
// 设置SameSite Cookie document.cookie ="session=abc123; SameSite=Lax; Secure";4. 前端框架(以 Vue 为例)
4.1 Vue 核心概念
讲解:Vue 是一套用于构建用户界面的渐进式框架,采用组件化、声明式编程。
解析:
- 组件:Vue 组件由模板、脚本、样式组成,可以是选项式 API 或组合式 API。
- 模板语法:基于 HTML 的模板,使用指令(如
v-bind、v-if、v-for)和插值{{ }}。 - 响应式系统:Vue 通过依赖追踪,在数据变化时自动更新视图。Vue 2 使用
Object.defineProperty,Vue 3 使用 Proxy。 - 实例:每个 Vue 应用通过
createApp创建根实例。 - 生命周期:组件从创建到销毁的各个阶段,如
created、mounted、updated、unmounted。
案例:
<template> <div> <p>{{ message }}</p> <button @click="reverseMessage">反转消息</button> </div> </template> <script> export default { data() { return { message: 'Hello Vue!' }; }, methods: { reverseMessage() { this.message = this.message.split('').reverse().join(''); } } }; </script> 4.2 生命周期与组合式 API
讲解:Vue 组件有生命周期钩子,组合式 API(Composition API)提供了更灵活的代码组织方式。
解析:
- 选项式 API 生命周期:
beforeCreate、created(实例创建前后)beforeMount、mounted(挂载前后)beforeUpdate、updated(更新前后)beforeUnmount、unmounted(卸载前后)
- 组合式 API:
setup函数是组合式 API 的入口,在beforeCreate之前执行。- 响应式数据:
ref、reactive。 - 生命周期钩子:
onMounted、onUpdated、onUnmounted等。 - 计算属性:
computed。 - 侦听器:
watch、watchEffect。
- 优势:更好的逻辑复用、类型推导、代码组织。
案例(组合式 API):
<template> <div> <p>计数: {{ count }}</p> <button @click="increment">+1</button> </div> </template> <script setup> import { ref, onMounted } from 'vue'; const count = ref(0); function increment() { count.value++; } onMounted(() => { console.log('组件已挂载'); }); </script> 4.3 虚拟 DOM 与 Diff 算法
讲解:Vue 通过虚拟 DOM 描述真实 DOM 结构,在数据变化时生成新的虚拟 DOM,与旧虚拟 DOM 进行 Diff 比较,找出最小更新范围,然后批量更新真实 DOM。
解析:
- Vue 的 Diff 策略(基于 Snabbdom):
- 同层比较,不跨级复用。
- 通过
key优化列表渲染,识别节点移动、添加、删除。key应稳定、唯一,避免使用索引。 - 双端比较算法(Vue 2)或快速 Diff(Vue 3),提升性能。
- Vue 3 优化:静态树提升、静态属性提升、事件缓存等,减少更新开销。
案例:
<template> <ul> <li v-for="item in items" :key="item.id">{{ item.name }}</li> </ul> </template> <script setup> import { ref } from 'vue'; const items = ref([ { id: 1, name: '苹果' }, { id: 2, name: '香蕉' } ]); </script> 4.4 状态管理
讲解:随着应用规模增大,需要统一管理共享状态。Vue 官方推荐 Vuex(Vue 2)或 Pinia(Vue 3)。
解析:
- Vuex:
- 核心概念:
state(状态)、getters(派生状态)、mutations(同步修改)、actions(异步操作)、modules(模块)。 - 原则:状态变更必须通过提交 mutation,便于追踪。
- 核心概念:
- Pinia:
- 更简洁的 API,完全支持 TypeScript,去除了 mutations,直接在 actions 中修改 state。
- 每个 store 独立定义,模块化自然。
- 对比:Pinia 已成为 Vue 官方推荐,替代 Vuex。
案例(Pinia):
// stores/counter.jsimport{ defineStore }from'pinia';exportconst useCounterStore =defineStore('counter',{state:()=>({count:0}),getters:{double:(state)=> state.count *2},actions:{increment(){this.count++;}}});// 组件中使用<script setup>import{ useCounterStore }from'./stores/counter';const counter =useCounterStore();</script><template><p>{{ counter.count }}*2={{ counter.double }}</p><button @click="counter.increment">增加</button></template>4.5 路由原理
讲解:前端路由根据 URL 变化渲染不同组件,无需刷新页面。Vue 官方路由库是 Vue Router。
解析:
- Hash 模式:利用
window.location.hash和hashchange事件。 - History 模式:利用 HTML5 History API(
pushState、replaceState),监听popstate事件。需要服务端配合避免 404。 - Vue Router 核心:
- 定义路由映射表。
<router-view>显示匹配的组件。<router-link>导航链接。- 动态路由、嵌套路由、导航守卫等。
案例:
// router/index.jsimport{ createRouter, createWebHistory }from'vue-router';import Home from'../views/Home.vue';import About from'../views/About.vue';const routes =[{path:'/',component: Home },{path:'/about',component: About }];const router =createRouter({history:createWebHistory(), routes });exportdefault router;// main.js 中使用 app.use(router);4.6 服务端渲染(SSR)
讲解:SSR 在服务器端渲染 HTML 字符串,发送到客户端,提升首屏加载速度和 SEO。Vue 官方 SSR 方案是 Vue + Vue Router + Vue Server Renderer,或使用 Nuxt 框架。
解析:
- Nuxt.js:基于 Vue 的 SSR 框架,提供文件路由、自动代码分割、静态站点生成等。
- 原理:服务器执行 Vue 组件,生成 HTML,客户端激活(hydration)使页面可交互。
- 优点:SEO 友好、更快首屏内容。
- 缺点:服务器负载增加、开发复杂度上升。
案例(Nuxt 3 页面):
<template> <div> <h1>{{ title }}</h1> <p>服务端渲染示例</p> </div> </template> <script setup> // 在服务端和客户端都会执行 const { data: title } = await useFetch('/api/title'); </script> 5. 工程化与工具
5.1 Webpack 原理与配置
讲解:Webpack 是一个模块打包工具,将项目中的模块(JS、CSS、图片等)打包成静态资源。
解析:
- 核心概念:
- Entry:入口文件,依赖图起点。
- Output:输出文件位置和名称。
- Loader:处理非 JS 文件(如 CSS、图片),将其转换为模块。
- Plugin:执行更广泛的任务(如压缩、提取 CSS、生成 HTML)。
- Mode:development/production,内置优化。
- 常用 Loader:
babel-loader(转译 ES6+)、css-loader(解析 CSS)、style-loader(注入 style 标签)、file-loader/url-loader(处理资源)。 - 常用 Plugin:
HtmlWebpackPlugin(生成 HTML)、MiniCssExtractPlugin(提取 CSS)、DefinePlugin(定义环境变量)、TerserPlugin(压缩 JS)。 - 构建流程:
- 初始化参数:从配置文件和 Shell 语句中读取合并参数。
- 开始编译:初始化 Compiler 对象,加载插件。
- 确定入口:根据 Entry 找到所有依赖模块。
- 编译模块:从入口开始,递归调用 Loader 转译模块。
- 完成模块编译:得到每个模块的最终内容和依赖关系。
- 输出资源:根据依赖关系组装 Chunk,生成文件列表。
- 写入文件系统。
案例(webpack.config.js 简化):
const HtmlWebpackPlugin =require('html-webpack-plugin');const MiniCssExtractPlugin =require('mini-css-extract-plugin'); module.exports ={entry:'./src/index.js',output:{filename:'bundle.[contenthash].js',path: path.resolve(__dirname,'dist')},module:{rules:[{test:/\.js$/,use:'babel-loader'},{test:/\.css$/,use:[MiniCssExtractPlugin.loader,'css-loader']}]},plugins:[newHtmlWebpackPlugin({template:'./src/index.html'}),newMiniCssExtractPlugin({filename:'styles.[contenthash].css'})]};5.2 Babel 原理
讲解:Babel 是一个 JavaScript 编译器,将 ES6+ 代码转换为向后兼容的版本。
解析:
- 工作流程:
- 解析(Parse):将源码解析为抽象语法树(AST)。
- 转换(Transform):遍历 AST,通过插件修改节点。
- 生成(Generate):将修改后的 AST 生成目标代码。
- 预设(Presets):一组插件的集合,如
@babel/preset-env根据目标环境自动转换。 - 插件(Plugins):单个转换功能,如
@babel/plugin-transform-arrow-functions。
案例(babel.config.js):
module.exports ={presets:[['@babel/preset-env',{targets:'> 0.25%, not dead'}]],plugins:['@babel/plugin-proposal-optional-chaining']};5.3 模块化
讲解:模块化解决命名冲突、依赖管理等问题。
解析:
- CommonJS(Node 环境):
module.exports/exports导出,require导入。同步加载。 - ES Module(ES6 标准):
export/export default导出,import导入。静态分析,异步加载,支持 Tree Shaking。 - AMD:
require.js实现,浏览器端异步加载。 - UMD:兼容 CommonJS 和 AMD 的通用模块定义。
案例:
// ES Module 导出exportconst name ='module';exportdefaultfunctionsayHi(){ console.log('Hi');}// 导入import sayHi,{ name }from'./module.js';5.4 Git 工作流
讲解:Git 是分布式版本控制系统,团队协作需规范流程。
解析:
- 常用命令:
git clone、git add、git commit、git push/pull、git branch、git merge、git rebase。 - 分支策略:
- Git Flow:
master(稳定)、develop(开发)、feature/*(功能)、release/*(发布)、hotfix/*(紧急修复)。 - GitHub Flow:
master始终可部署,从master拉取功能分支,完成后提 PR 合并。 - GitLab Flow:环境分支(
pre-production、production)结合合并请求。
- Git Flow:
- Merge 与 Rebase 区别:
merge保留历史分支,rebase使历史线性,但需注意公共分支不要 rebase。
案例:
# 创建功能分支git checkout -b feature/new-button # 开发后提交gitadd.git commit -m"add new button"# 合并到主分支git checkout main git merge feature/new-button 5.5 CI/CD 基础
讲解:持续集成/持续部署自动化构建、测试、部署流程。
解析:
- CI:开发频繁合并代码到主干,自动构建和测试,及早发现问题。
- CD:通过 CI 验证后,自动部署到预发布或生产环境。
- 常见工具:Jenkins、GitHub Actions、GitLab CI、Travis CI。
- 流程示例:push 代码 → 触发 CI 运行测试 → 测试通过 → 构建镜像/打包 → 部署到服务器。
案例(GitHub Actions 简化):
name: CI/CD on:[push]jobs:build:runs-on: ubuntu-latest steps:-uses: actions/checkout@v2 -run: npm install -run: npm test -run: npm run build -name: Deploy uses: peaceiris/actions-gh-pages@v3 with:github_token: ${{ secrets.GITHUB_TOKEN }}publish_dir: ./dist 6. 性能优化
6.1 加载优化
- 减少 HTTP 请求:合并 CSS/JS 文件,使用雪碧图,内联小资源。
- 资源压缩:Gzip/Brotli 压缩文本文件,压缩图片(WebP、压缩工具)。
- 使用 CDN:将静态资源分布到全球节点,加速用户访问。
- 懒加载:图片、路由组件等按需加载,减少首屏资源。
- 预加载/预连接:
<link rel="preload">预加载关键资源,dns-prefetch、preconnect提前解析 DNS 和建立连接。
案例:
<!-- 预加载关键样式 --><linkrel="preload"href="main.css"as="style"><!-- 预连接第三方域名 --><linkrel="preconnect"href="https://api.example.com"><!-- 图片懒加载 --><imgsrc="placeholder.jpg"data-src="real.jpg"loading="lazy"alt="...">6.2 渲染优化
- 减少重排重绘:参见 3.2 节。
- 避免内存泄漏:及时解绑事件、清除定时器、销毁全局变量。
- 使用
will-change:提示浏览器准备优化某个元素的变化。 - 长列表优化:虚拟列表(只渲染可视区域),如 vue-virtual-scroller。
- Web Worker:将复杂计算放在后台线程,避免阻塞主线程。
案例:
// 使用 will-change.animated { will-change: transform, opacity;}// Vue 中使用虚拟列表(假设有大量数据)<template><RecycleScroller :items="list":item-size="50" key-field="id" v-slot="{ item }"><div>{{ item.name }}</div></RecycleScroller></template>6.3 打包优化
- 代码分割:Webpack 的
splitChunks提取公共依赖,路由懒加载。 - Tree Shaking:移除未使用的代码,需 ES Module 支持。
- 按需加载:第三方库如 Lodash 使用
lodash-es或插件按需引入。 - 压缩代码:
TerserPlugin压缩 JS,CssMinimizerPlugin压缩 CSS。 - 图片优化:压缩图片,使用
url-loader将小图片转为 base64。
案例:
// Vue 路由懒加载const routes =[{path:'/about',component:()=>import('./views/About.vue')}];// Webpack splitChunksoptimization:{splitChunks:{chunks:'all',cacheGroups:{vendor:{test:/[\\/]node_modules[\\/]/,name:'vendors'}}}}6.4 性能指标
讲解:以用户为中心的性能指标,用于量化体验。
解析:
- FP(First Paint):首次绘制像素。
- FCP(First Contentful Paint):首次绘制任何内容(文本、图片)。
- LCP(Largest Contentful Paint):最大内容绘制时间,衡量主要内容加载速度。
- FID(First Input Delay):首次输入延迟,衡量交互响应性。
- CLS(Cumulative Layout Shift):累计布局偏移,衡量视觉稳定性。
- TTI(Time to Interactive):可交互时间。
- 工具:Lighthouse、Chrome DevTools Performance 面板。
案例:
// 使用 Performance API 测量 FCPnewPerformanceObserver((entryList)=>{for(const entry of entryList.getEntries()){ console.log('FCP:', entry.startTime);}}).observe({type:'paint',buffered:true});7. 数据结构与算法(前端常考)
7.1 常见数据结构
- 数组:连续内存,查找 O(1),插入删除 O(n)。
- 链表:非连续,插入删除 O(1),查找 O(n)。
- 栈:后进先出(LIFO),如括号匹配。
- 队列:先进先出(FIFO),如任务队列。
- 树:二叉树、二叉搜索树、平衡树(红黑树)。
- 哈希表:键值对,查找 O(1),处理冲突(链表法、开放寻址)。
案例:
// 栈应用:括号匹配functionisValid(s){const stack =[];const map ={'(':')','[':']','{':'}'};for(let c of s){if(map[c]){ stack.push(c);}else{const top = stack.pop();if(map[top]!== c)returnfalse;}}return stack.length ===0;} console.log(isValid('()[]{}'));// true7.2 排序算法
- 冒泡排序:O(n²),稳定。
- 快速排序:O(n log n) 平均,不稳定,分治思想。
- 归并排序:O(n log n),稳定,分治+合并。
- 选择排序:O(n²),不稳定。
- 插入排序:O(n²),稳定,适合小规模数据。
案例:
// 快速排序functionquickSort(arr){if(arr.length <=1)return arr;const pivot = arr[0];const left =[], right =[];for(let i =1; i < arr.length; i++){ arr[i]< pivot ? left.push(arr[i]): right.push(arr[i]);}return[...quickSort(left), pivot,...quickSort(right)];} console.log(quickSort([3,6,8,10,1,2,1]));// [1,1,2,3,6,8,10]7.3 递归与迭代
讲解:递归函数调用自身,需有终止条件;迭代通过循环实现。
解析:
- 递归缺点:可能导致栈溢出,性能较低(可优化为尾递归)。
- 适用场景:树的遍历、分治算法。
- 示例:斐波那契数列、汉诺塔。
案例:
// 递归求斐波那契(有大量重复计算,可优化)functionfib(n){if(n <=1)return n;returnfib(n-1)+fib(n-2);}// 迭代优化functionfibIter(n){let a =0, b =1;for(let i =2; i <= n; i++){[a, b]=[b, a + b];}return n ===0? a : b;}7.4 常见算法题
- 数组去重:利用 Set、filter + indexOf、reduce。
- 数组扁平化:递归、
flat(Infinity)、reduce + concat。 - 函数柯里化:将多参数函数转换为一系列单参数函数。
- 节流/防抖:见 2.8。
- 深拷贝:见 2.7。
- 手写 Promise:考察对异步的理解。
- 查找最长无重复子串:滑动窗口。
案例:
// 数组扁平化functionflatten(arr){return arr.reduce((acc, val)=> Array.isArray(val)? acc.concat(flatten(val)): acc.concat(val),[]);} console.log(flatten([1,[2,[3,4],5]]));// [1,2,3,4,5]// 函数柯里化functioncurry(fn){returnfunctioncurried(...args){if(args.length >= fn.length){returnfn.apply(this, args);}else{return(...args2)=>curried.apply(this, args.concat(args2));}};}constadd=(a,b,c)=> a+b+c;const curriedAdd =curry(add); console.log(curriedAdd(1)(2)(3));// 68. 设计模式与架构
8.1 常见设计模式
- 单例模式:确保一个类只有一个实例,如全局状态管理(Pinia store)。
- 观察者模式:主题维护观察者列表,状态变化时通知所有观察者(如 Vue 的响应式系统)。
- 发布订阅模式:类似观察者,但通过事件中心解耦,如 EventBus。
- 工厂模式:创建对象而不指定具体类,如 Vue 的
createApp。 - 策略模式:定义一系列算法,封装起来可互换,如表单验证策略。
- 代理模式:为对象提供替代或占位符,控制访问,如虚拟代理(图片懒加载)。
案例(发布订阅):
classEventBus{constructor(){this.events ={};}on(event, listener){(this.events[event]||(this.events[event]=[])).push(listener);}emit(event, data){(this.events[event]||[]).forEach(listener=>listener(data));}off(event, listener){if(!this.events[event])return;this.events[event]=this.events[event].filter(l=> l !== listener);}}const bus =newEventBus(); bus.on('login',(user)=> console.log('登录:', user)); bus.emit('login',{name:'Alice'});8.2 MVC / MVVM 模式
- MVC:Model(数据)、View(视图)、Controller(业务逻辑)。用户操作→Controller→更新Model→更新View。
- MVVM:Model、View、ViewModel(数据绑定器)。通过双向绑定,View 变化自动更新 Model,反之亦然。如 Vue 的响应式系统。
案例:Vue 是 MVVM 的典型实现,ViewModel 对应组件实例,Model 对应 data,View 对应模板。
9. 软技能与开放性题目
- 项目经验:能清晰描述项目背景、技术选型、个人贡献、难点及解决方案。
- 团队协作:沟通方式、代码审查、冲突解决。
- 学习能力:关注新技术、阅读源码、参与社区。
- 开放性题目:如“如果让你设计一个前端监控系统,你会怎么做?”可从数据采集(性能、错误、行为)、上报策略、数据可视化等方面展开。
案例:回答前端监控系统设计时,可提及使用 Performance API 收集指标,通过 Beacon API 上报,利用错误事件监听 JS 错误,使用 Sentry 等工具。
总结
前端面试覆盖范围广、深度要求高。本文从基础到进阶,系统梳理了 HTML/CSS、JavaScript、浏览器网络、框架(以 Vue 为例)、工程化、性能优化、算法设计模式等核心知识点,并给出了深入解析及案例。希望你能结合这些内容,举一反三,在面试中不仅“知其然”,更能“知其所以然”,展现出作为一名高级前端开发工程师的技术底蕴和解决问题的能力。祝你面试顺利!