跳到主要内容前端面试核心知识点全解析 | 极客日志JavaScript大前端算法
前端面试核心知识点全解析
系统梳理了前端面试核心知识点,涵盖 HTML/CSS 基础、JavaScript 核心原理、浏览器渲染与网络协议、Vue 框架机制、工程化构建工具、性能优化策略以及数据结构算法与设计模式。通过理论讲解与代码案例,帮助开发者深入理解技术细节,提升面试竞争力。
雪落无声1 浏览 作为一名前端高级开发人员,面试不仅考察知识点的记忆,更关注对原理的理解、工程化的思考以及解决复杂问题的能力。本文将从 HTML/CSS、JavaScript、浏览器与网络、框架、工程化、性能优化、算法与设计模式等多个维度,系统梳理前端面试中的核心知识点,并提供深入解析及案例,帮助你在面试中展现出真正的技术深度。
1. HTML & CSS 基础
1.1 语义化 HTML
讲解:语义化 HTML 是指使用具有明确含义的标签(如 <header>、<nav>、<article>、<section>)来描述网页结构,而不是单纯使用 <div> 和 <span>。
- SEO 友好:搜索引擎爬虫依赖语义标签理解页面内容,有助于提升排名。
- 可访问性:屏幕阅读器等辅助技术可以更好地解析页面,为视障用户提供良好体验。
- 代码可维护性:团队协作时,语义化标签让代码结构清晰易懂。
- 常见语义标签:
<header>、<footer>、<main>、<aside>、<article>、<section>、<nav>。
<div class="header">
<div class="logo">MySite</div>
<div class="nav">
<a href="/">首页</a>
<a href="/about">关于</a>
</div>
</div>
<header>
<h1 class="logo">MySite</h1>
<nav>
<ul>
<li><a href="/">首页</a></li>
<li><a href="/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;
}
.box-border {
box-sizing: border-box;
width: 100px;
padding: 10px;
border: 5px solid black;
margin: 10px;
}
1.3 布局方式
1.3.1 浮动与清除浮动
讲解:float 使元素脱离文档流,向左或向右浮动,常用于文字环绕图片或实现多列布局。
- 浮动影响:父容器高度塌陷(因为浮动元素不占文档流高度)。
- 清除浮动方法:
- 在父容器末尾添加空元素并设置
clear: both。
- 父容器触发 BFC(如
overflow: hidden)。
- 使用伪元素:
.clearfix::after { content: ""; display: table; clear: both; }。
<div class="container clearfix">
<div class="float-left">浮动元素</div>
<div class="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 定位元素上生效,且受层叠上下文影响。
<div class="parent" style="position: relative; height: 200px; background: #eee;">
<div class="child" style="position: absolute; bottom: 10px; right: 10px;">绝对定位</div>
</div>
<div class="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> 元素,根据分辨率加载合适图片。
<img srcset="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 文件。
$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。
- 优点:避免样式冲突,清晰的结构关系。
<div class="card">
<div class="card__header">
<h2 class="card__title">标题</h2>
</div>
<div class="card__body">内容</div>
<div class="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 限制。
<div style="position: relative; z-index: 1;">
<div style="position: absolute; z-index: 999;">这个 999 受父级 1 限制</div>
</div>
<div style="position: relative; z-index: 2;">
<div style="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(typeof 42);
console.log(typeof 'hello');
console.log(typeof true);
console.log(typeof undefined);
console.log(typeof null);
console.log(typeof {});
console.log(typeof function(){});
console.log([] instanceof Array);
console.log({} instanceof Object);
console.log(Object.prototype.toString.call([]));
console.log(Object.prototype.toString.call(null));
2.2 作用域与闭包
讲解:作用域决定了变量的可访问范围。JavaScript 采用词法作用域(静态作用域),函数的作用域在定义时确定。闭包是指有权访问另一个函数作用域中变量的函数。
- 作用域链:当访问变量时,从当前作用域开始向上查找,直到全局。
- 闭包的形成:内部函数引用了外部函数的变量,即使外部函数执行完毕,变量仍被内部函数引用,不会被垃圾回收。
- 常见用途:
- 封装私有变量(模块模式)。
- 函数柯里化。
- 循环中使用
var 创建多个闭包(通常用 IIFE 或 let 解决)。
- 内存泄漏:闭包不当会导致内存无法释放,应避免无限制使用。
function createCounter() {
let count = 0;
return {
increment: () => ++count,
decrement: () => --count,
getCount: () => count
};
}
const counter = createCounter();
console.log(counter.increment());
console.log(counter.increment());
console.log(counter.getCount());
2.3 原型与原型链
讲解:JavaScript 通过原型实现继承。每个对象都有一个 __proto__ 属性指向其构造函数的原型对象 prototype。原型链由多个对象的 __proto__ 链接而成。
- 构造函数:函数本身也是对象,拥有
prototype 属性。通过 new 调用构造函数创建实例,实例的 __proto__ 指向构造函数的 prototype。
- 原型链查找:访问对象属性时,如果对象自身没有,则沿着
__proto__ 向上查找,直到 null。
- 原型链终点:
Object.prototype.__proto__ === null。
- 继承方式:
- 原型链继承:
Child.prototype = new Parent()。
- 组合继承:原型链 + 构造函数。
- ES6
class 语法糖(本质仍是原型链)。
instanceof 原理:检测右侧构造函数的 prototype 是否在左侧对象的原型链上。
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(`${this.name} makes a sound.`);
};
function Dog(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 = new Dog('Rex', 'Husky');
d.speak();
d.bark();
console.log(d instanceof Dog);
console.log(d instanceof Animal);
2.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 > 显式绑定 > 隐式绑定 > 默认绑定。
function greet(greeting, punctuation) {
console.log(greeting + ', ' + this.name + punctuation);
}
const person = { name: 'Alice' };
greet.call(person, 'Hello', '!');
greet.apply(person, ['Hi', '?']);
const bound = greet.bind(person, 'Hey');
bound('!!');
2.5 异步编程
2.5.1 回调函数
- 优点:简单直观。
- 缺点:回调地狱(多层嵌套)、错误处理困难、代码可读性差。
function fetchData(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 捕获。
function asyncTask(shouldResolve) {
return new Promise((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 并发执行,避免串行等待。
async function fetchData() {
try {
const result = await asyncTask(true);
console.log(result);
const data = await asyncTask(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');
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');
2.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);
const deep = JSON.parse(JSON.stringify(original));
deep.b.c = 4;
console.log(original.b.c);
2.8 防抖与节流
节流(throttle):规定一个单位时间内,只能触发一次函数。适用于滚动加载、频繁点击。
function throttle(fn, interval) {
let lastTime = 0;
return function (...args) {
const now = Date.now();
if (now - lastTime >= interval) {
fn.apply(this, args);
lastTime = now;
}
};
}
防抖(debounce):在事件被触发 n 秒后执行回调,如果在这 n 秒内又被触发,则重新计时。适用于输入框搜索、窗口 resize。
function debounce(fn, delay) {
let timer = null;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
<input id="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);
const evens = arr.filter(x => x % 2 === 0);
const sum = arr.reduce((acc, cur) => acc + cur, 0);
const obj = { a: 1, b: 2 };
Object.keys(obj).forEach(key => console.log(key, obj[key]));
const merged = Object.assign({}, obj, { c: 3 });
3. 浏览器与网络
3.1 浏览器渲染原理
讲解:浏览器从获取 HTML 到渲染出页面的过程。
- 解析 HTML:构建 DOM 树。
- 解析 CSS:构建 CSSOM 树。
- 合并:生成渲染树(Render Tree),只包含可见节点。
- 布局(Layout/Reflow):计算每个节点的几何位置。
- 绘制(Paint):将渲染树绘制到屏幕。
- 合成(Composite):分层绘制,利用 GPU 加速。
- 关键点:CSS 不会阻塞 DOM 解析,但会阻塞渲染;JS 会阻塞 DOM 解析(除非标记
async 或 defer)。
<script src="slow.js"></script>
<script async src="async.js"></script>
<script defer src="defer.js"></script>
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;';
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:适用于主域相同子域不同的情况(已过时)。
function jsonp(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');
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-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/>
3.6 Web 安全
3.6.1 XSS(跨站脚本攻击)
讲解:攻击者注入恶意脚本到可信网站,当用户浏览时执行。
- 反射型:恶意脚本通过 URL 参数注入,后端未过滤直接返回。
- 存储型:恶意脚本存储在服务器数据库,如评论区,每次访问都触发。
- DOM 型:纯前端漏洞,通过修改 DOM 执行脚本。
- 防御:
- 输入过滤(对用户输入进行转义)。
- 输出编码(使用
textContent 而不是 innerHTML)。
- 设置
Content-Security-Policy(CSP)限制资源加载。
- 使用 HttpOnly Cookie 防止 Cookie 被脚本窃取。
function escapeHTML(str) {
return str.replace(/[&<>"']/g, function(m) {
if (m === '&') return '&';
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 头。
- 使用验证码(重要操作)。
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。
- 优势:更好的逻辑复用、类型推导、代码组织。
<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。
import { defineStore } from 'pinia';
export const 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> 导航链接。
- 动态路由、嵌套路由、导航守卫等。
import { 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
});
export default router;
4.6 服务端渲染(SSR)
讲解:SSR 在服务器端渲染 HTML 字符串,发送到客户端,提升首屏加载速度和 SEO。Vue 官方 SSR 方案是 Vue + Vue Router + Vue Server Renderer,或使用 Nuxt 框架。
- Nuxt.js:基于 Vue 的 SSR 框架,提供文件路由、自动代码分割、静态站点生成等。
- 原理:服务器执行 Vue 组件,生成 HTML,客户端激活(hydration)使页面可交互。
- 优点:SEO 友好、更快首屏内容。
- 缺点:服务器负载增加、开发复杂度上升。
<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: [
new HtmlWebpackPlugin({ template: './src/index.html' }),
new MiniCssExtractPlugin({ 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。
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 的通用模块定义。
export const name = 'module';
export default function sayHi() {
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)结合合并请求。
- Merge 与 Rebase 区别:
merge 保留历史分支,rebase 使历史线性,但需注意公共分支不要 rebase。
git checkout -b feature/new-button
git add .
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 运行测试 → 测试通过 → 构建镜像/打包 → 部署到服务器。
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 和建立连接。
<link rel="preload" href="main.css" as="style">
<link rel="preconnect" href="https://api.example.com">
<img src="placeholder.jpg" data-src="real.jpg" loading="lazy" alt="...">
6.2 渲染优化
- 减少重排重绘:参见 3.2 节。
- 避免内存泄漏:及时解绑事件、清除定时器、销毁全局变量。
- 使用
will-change:提示浏览器准备优化某个元素的变化。
- 长列表优化:虚拟列表(只渲染可视区域),如 vue-virtual-scroller。
- Web Worker:将复杂计算放在后台线程,避免阻塞主线程。
.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。
const routes = [
{ path: '/about', component: () => import('./views/About.vue') }
];
optimization: {
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 面板。
new PerformanceObserver((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),处理冲突(链表法、开放寻址)。
function isValid(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) return false;
}
}
return stack.length === 0;
}
console.log(isValid('()[]{}'));
7.2 排序算法
- 冒泡排序:O(n²),稳定。
- 快速排序:O(n log n) 平均,不稳定,分治思想。
- 归并排序:O(n log n),稳定,分治 + 合并。
- 选择排序:O(n²),不稳定。
- 插入排序:O(n²),稳定,适合小规模数据。
function quickSort(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]));
7.3 递归与迭代
讲解:递归函数调用自身,需有终止条件;迭代通过循环实现。
- 递归缺点:可能导致栈溢出,性能较低(可优化为尾递归)。
- 适用场景:树的遍历、分治算法。
- 示例:斐波那契数列、汉诺塔。
function fib(n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
function fibIter(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:考察对异步的理解。
- 查找最长无重复子串:滑动窗口。
function flatten(arr) {
return arr.reduce((acc, val) => Array.isArray(val) ? acc.concat(flatten(val)) : acc.concat(val), []);
}
console.log(flatten([1, [2, [3, 4], 5]]));
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return (...args2) => curried.apply(this, args.concat(args2));
}
};
}
const add = (a, b, c) => a + b + c;
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3));
8. 设计模式与架构
8.1 常见设计模式
- 单例模式:确保一个类只有一个实例,如全局状态管理(Pinia store)。
- 观察者模式:主题维护观察者列表,状态变化时通知所有观察者(如 Vue 的响应式系统)。
- 发布订阅模式:类似观察者,但通过事件中心解耦,如 EventBus。
- 工厂模式:创建对象而不指定具体类,如 Vue 的
createApp。
- 策略模式:定义一系列算法,封装起来可互换,如表单验证策略。
- 代理模式:为对象提供替代或占位符,控制访问,如虚拟代理(图片懒加载)。
class EventBus {
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 = new EventBus();
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 为例)、工程化、性能优化、算法设计模式等核心知识点,并给出了深入解析及案例。希望你能结合这些内容,举一反三,在面试中不仅'知其然',更能'知其所以然',展现出作为一名高级前端开发工程师的技术底蕴和解决问题的能力。祝你面试顺利!
微信扫一扫,关注极客日志
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online