三剑客

div 上下居中对齐的方式

常用 Flexbox 布局

1
2
3
4
5
.parent {
display: flex;
align-items: center; /* 垂直居中 */
/* justify-content: center; 如果需要水平居中则加上这行 */
}

深拷贝与浅拷贝

浅拷贝 深拷贝
定义 在栈内存中重新开辟一块内存空间,并将拷贝对象储存在栈内存中的数据存放到其中。 会另外创造一个一模一样的对象
优缺点 浅拷贝只复制了引用,所以修改新对象会影响到原对象 修改新对象不会影响到原对象
实现方法 使用赋值运算符(=)或者Object.assign()函数进行拷贝 递归拷贝JSON.parse(JSON.stringify(obj)) 或者…扩展运算符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 浅拷贝
const a = [1, 2, 3];
const b = a;
b[0] = 4;
console.log(a); // [4, 2, 3]
console.log(b); // [4, 2, 3]


// 深拷贝
const a = [1, 2, 3];
const b = […a]; // 这只适用于一层深拷贝
const c = JSON.parse(JSON.stringify(a)); // 深拷贝 如果是个对象有函数或者undefind时会有问题
c[0] = 4;
console.log(a); // [1, 2, 3]
console.log(c); // [4, 2, 3]


// 深拷贝问题代码示例
const obj = {
name: '前端',
age: undefined, // 问题1:undefined
sayHi: function() { // 问题2:函数
console.log('hi');
},
address: {
city: '上海',
detail: undefined // 问题3:嵌套对象里的 undefined
}
};

const copy = JSON.parse(JSON.stringify(obj));

console.log(copy);
// 输出结果:
// {
// name: '前端',
// address: { city: '上海' } // detail 属性直接消失了!
// }
// 注意:age 和 sayHi 也完全消失了


// null值不影响
const safeObj = { a: 1, b: 'hello', c: true, d: null };
const copy = JSON.parse(JSON.stringify(safeObj)); // ✅ 完美深拷贝

cookie、sessionStorage、localStorage 的区别

cookie 是一种在客户端存储少量数据并在每个请求中发送给服务器的机制,而 session 则是在服务器端存储用户状态信息,并通过在客户端和服务器之间传递 Session ID 来保持会话状态。它们的区别在于存储的有效期和作用域的不同。为了解决 HTTP 无状态的问题,通常使用 Cookie 和 Session 等机制来在客户端和服务器之间保持状态。

特性 Cookie localStorage sessionStorage
生命周期 默认会话级(关闭浏览器即失效) 可手动设置 ExpiresMax-Age 延长 永久 除非用户手动清除或通过代码删除 会话级 仅当前标签页有效,关闭标签页即清除
存储大小 约 4KB 5-10MB(不同浏览器略有差异) 约 5MB(不同浏览器略有差异)
作用域(同源策略) 域名 + 路径(可设Path) 同源且同路径才能共享 域名 + 协议 + 端口 同源下所有标签页/窗口共享 域名 + 协议 + 端口 仅限同一标签页的同一源
与服务端交互 自动携带(每次HTTP请求都会发送,影响性能) 不自动发送(纯前端存储) 不自动发送(纯前端存储)

作用域的详细解释

  • Cookie 的作用域最窄:默认只对当前路径(/)及其子路径有效,但可以通过 PathDomain 参数扩大范围。
  • localStorage 的作用域是“同源窗口共用”:打开同一个网站的多个标签页,它们共享同一个 localStorage 数据(监听 storage 事件可实现跨标签页通信)。
  • sessionStorage 的作用域是“独立标签页”:即使用户在同一网站通过“新标签页打开链接”,新标签页也会拥有独立的 sessionStorage,与原来的互不影响。

<a>
用户 → 点击 → 跳转

<link>
浏览器 → 发现资源 → 加载/关联

<a> <link>
主要用途 页面导航 引入/声明外部资源
用户是否点击 ✅ 通常点击 ❌ 不用于点击
核心属性 href rel + href
是否显示文字
示例 <a href="https://www.baidu.com">百度</a> <link rel="stylesheet" href="style.css">

注意:这里的rel名称是固定的,常用的有如下:

rel 值 用途
icon 网站标签页图标(favicon)
stylesheet 引入 CSS 样式表

Vue 中的跨域问题

vue3vite.config.js 中配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default defineConfig({
server: {
host: '0.0.0.0', // 允许通过IP地址访问
port: 92, // 设置你想要的端口号
allowedHosts: ['pna.vrmmo.online'], // 允许通过域名访问
proxy: {
'/api/paper': {
target: 'http://localhost:8092',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
},
'/api': {
target: 'http://localhost:8092',
changeOrigin: true
}
}
}
})

浏览器的同源策略会阻止前端(localhost:92)直接请求后端(localhost:8092),产生跨域。Vite 开发服务器提供了 代理(proxy) 功能,让前端请求先发到 Vite 自身,再由 Vite 转发给后端,从而绕过浏览器的跨域限制。

流程

  1. 前端请求 http://localhost:92/api/xxx
  2. Vite 开发服务器拦截该请求
  3. 转发到 http://localhost:8092/api/xxx(服务器之间不存在跨域)
  4. 将后端响应返回给前端

/api/paper 单独配置了 rewrite 去掉 /api 前缀,说明 paper 模块的后端接口路径不带 /api 前缀。

如何优化网站性能

  1. 许多的小图片整合到一张大图片中(精灵图)减少网页的http请求,提升网页加载速度。
  2. 利用浏览器缓存。
  3. 图片lazyload 懒加载 提高用户体验。

浏览器缓存参考 面经-计算机网络 中的强缓存和协商缓存

JS 中操作数组的方法

顺序 方法名 功能 返回值 是否改变原数组 版本
1 push() (在结尾)向数组添加一或多个元素 返回新数组长度 Y ES5-
2 unshift() (在开头)向数组添加一或多个元素 返回新数组长度 Y ES5-
3 pop() 删除数组的最后一位 返回被删除的数据 Y ES5-
4 shift() 移除数组的第一项 返回被删除的数据 Y ES5-
5 reverse() 反转数组中的元素 返回反转后数组 Y ES5-
6 sort() 以字母顺序(字符串Unicode码点)对数组进行排序 返回新数组 Y ES5-
7 splice() 在指定位置删除指定个数元素,再增加任意个数元素(实现数组任意位置的增删改) 返回删除的数据所组成的数组 Y ES5-
8 concat() 通过合并(连接)现有数组来创建一个新数组 返回合并之后的数组 N ES5-
9 join() 用特定的字符,将数组拼接形成字符串(默认”,”) 返回拼接后的新数组 N ES5-
10 slice() 截切指定位置的数组 被截切的元素形成的新的数组 N ES5-
11 toString() 将数组转换为字符串 新数组 N ES5-
12 valueOf() 查询数组原始值 数组的原始值 N ES5-
13 indexOf() 查询某个元素在数组中第一次出现的位置 存在该元素,返回下标,不存在返回 -1 N ES5-
14 lastIndexOf() 反向查询数组某个元素在数组中第一次出现的位置 存在该元素,返回下标,不存在返回 -1 N ES5-
15 forEach() (迭代)遍历数组,每次循环中执行传入的回调函数 无/(undefined) N ES5-
16 map() (迭代)遍历数组,每次循环时执行传入的回调函数,根据回调函数的返回值,生成一个新的数组 有/自定义 N ES5-
17 filter() (迭代)遍历数组,每次循环时执行传入的回调函数,回调函数返回一个条件,把满足条件的元素筛选出来放到新数组中 满足条件的元素组成的新数组 N ES5-
18 every() (迭代)判断数组中所有的元素是否满足某个条件 全都满足返回true 只要有一个不满足返回false N ES5-
19 some() (迭代)判断数组中是否存在,满足某个条件的元素 只要有一个元素满足条件就返回true,都不满足返回false N ES5-
20 reduce() (归并)遍历数组,每次循环时执行传入的回调函数,回调函数会返回一个值,将该值作为初始值prev,传入到下一次函数中 最终操作的结果 N ES5-
21 reduceRight() (归并)用法同reduce,只不过是从右向左 同reduce N ES5-
22 includes() 判断一个数组是否包含一个指定的值 是返回 true,否则 false N ES6
23 Array.from() 接收伪数组,返回对应的真数组 对应的真数组 N

VUE

对于MVVM的理解?

MVVM 是 Model-View-ViewModel 的缩写,MVVM 的设计原理是基于 MVC 的;它主要的优势在于 View 和 Model 之间是双向数据传递的,视图改变数据就可以改变,数据改变了视图也跟着改变。

对比项 MVC MVVM
通信方向 用户操作 → Controller → Model → View(单向为主) View ↔ ViewModel ↔ Model(双向自动同步)
Controller/ViewModel职责 Controller手动控制数据流向和视图更新。 ViewModel通过数据绑定自动同步,无需手动操作。
代码耦合度 View和Model之间可能直接关联,耦合较高。 View和Model完全隔离,只通过ViewModel通信,耦合度低。
适用场景 后端开发、小型前端项目。 复杂的前端单页应用(SPA),如Vue、React(类MVVM)、Angular。

Vue2/3的生命周期

Vue 的生命周期是指一个 Vue 实例从创建、挂载、更新到销毁的完整过程。在这个过程中,Vue 提供了一系列的生命周期钩子函数,让开发者可以在特定的阶段执行自己的逻辑。

Vue 2 的生命周期(共 8 个阶段,11 个钩子)

阶段 钩子函数 触发时机 能否操作DOM 适用场景
创建阶段 beforeCreate 实例初始化后,数据观测和事件配置之前 ❌ 否 很少使用,可用于插件初始化
created 实例创建完成,数据观测、计算属性、方法已配置,但尚未挂载 ❌ 否 最常用:发起 Ajax 请求、初始化数据
挂载阶段 beforeMount 模板编译完成,即将挂载到DOM之前 ❌ 否 很少使用
mounted 实例已挂载到DOMel 被新生成的 vm.$el 替换 ✅ 是 操作 DOM、使用第三方库(如 ECharts)初始化图表
更新阶段 beforeUpdate 数据变化后,虚拟DOM重新渲染和打补丁之前 ❌ 否 在更新前访问现有 DOM 状态,如获取滚动位置
updated 虚拟DOM重新渲染并完成DOM更新后 ✅ 是 执行依赖于 DOM 的操作,但注意避免在此修改数据(死循环)
销毁阶段 beforeDestroy 实例销毁之前this 仍可访问) ✅ 是 清除定时器、取消订阅、解绑事件监听
destroyed 实例销毁完成后,所有指令解绑,事件监听移除 ✅ 是 收尾清理工作

此外,Vue 2 还提供了 3 个特殊场景的钩子:

钩子函数 触发时机
activated keep-alive 缓存的组件激活时触发
deactivated keep-alive 缓存的组件停用时触发
errorCaptured 当捕获到来自子孙组件的错误时触发

Vue 3 的生命周期

Vue 3 保留了 Vue 2 的核心生命周期,但在命名和用法上做了调整:

Vue 2 钩子 Vue 3 钩子(Options API) 变化说明
beforeCreate beforeCreate 名称不变
created created 名称不变
beforeMount beforeMount 名称不变
mounted mounted 名称不变
beforeUpdate beforeUpdate 名称不变
updated updated 名称不变
beforeDestroy beforeUnmount ⚠️ 重命名,语义更准确
destroyed unmounted ⚠️ 重命名,语义更准确
activated activated 配合 <KeepAlive> 使用
deactivated deactivated 配合 <KeepAlive> 使用
errorCaptured errorCaptured 名称不变

注:beforeCreatecreated 在 Vue 3 中仍然保留,但官方更推荐使用 setup() 替代。

Vue组件间的参数传递 和父子组件方法调用

Vue的路由实现:hash模式 和 history模式区别,上线有什么区别。

在 Vue Router 中,hash 模式history 模式是两种前端路由实现方式,它们的核心区别在于如何管理 URL 以及如何与服务器交互

对比维度 Hash 模式(默认模式) History 模式
URL 格式 带有 # 符号,如 /#/about #,如 /about
浏览器支持 兼容所有现代浏览器(包括 IE) 需要支持 HTML5 History API(IE10+)
服务器配置 无需特殊配置,所有请求都返回 index.html 需要服务器配置,所有路由路径都要指向 index.html

Vue路由的钩子函数 (路由守卫)

Vue-router的跳转原理:
vuex是什么?怎么使用?哪种功能场景使用它?
对keep-alive 的了解?
vue深度监听(watch)
vue 怎么缓存 keep-alive
缓存了 突然需要发送请求换数据怎么办
vue原理
v-if和v-for哪个优先级更高? 如果两个同时出现,应该怎么优化得到更好的性能?
你知道vue中的key 和工作原理么?说说你对它的理解
你怎么理解vue中的 diff 算法?
vue3.0 生命周期
vue2 与vue3 的区别
vue和react的区别 (三个角度分析)