今天给大家分享一波最新的大厂面试题,内容有点干,备好水准备开始吧~
1. vue响应式原理
vue2 通过 Object.defineProperty
递归遍历对象的每个属性,将属性转换为 getter
和 setter
,从而拦截对数据的读写操作,每个属性对应一个 Dep
对象,用于管理所有依赖(Watcher)
javascript
// 简化版本
function defineReactive(obj, key) {
const dep = new Dep(); // 每个属性对应一个 Dep
let value = obj[key];
Object.defineProperty(obj, key, {
get() {
if (Dep.target) {
dep.addSub(Dep.target); // 收集依赖
}
return value;
},
set(newValue) {
if (value === newValue) return;
value = newValue;
dep.notify(); // 触发更新
},
});
}
class Dep {
static target = null; // 静态属性,指向当前正在计算的 Watcher
constructor() {
this.subs = []; // 存储所有订阅者(Watcher)
}
// 添加依赖
addSub(watcher) {
this.subs.push(watcher);
}
// 通知所有依赖更新
notify() {
this.subs.forEach(watcher => watcher.update());
}
}
vue3使用 Proxy
代理对象,拦截对数据的 读取(get) 和 修改(set) 操作,实现深度响应式。 与 vue2 不同可以直接代理整个对象,无需递归遍历属性。通过 effect
副作用函数 和 ReactiveEffect
类 替代了 vue2 的 Dep
和 Watcher
scss
// 简化版本
function reactive(target) {
return new Proxy(target, {
get(target, key, receiver) {
track(target, key); // 收集依赖
const result = Reflect.get(target, key, receiver);
// 递归代理嵌套对象(惰性代理,只有访问时才处理)
return isObject(result) ? reactive(result) : result;
},
set(target, key, value, receiver) {
const oldValue = target[key];
const result = Reflect.set(target, key, value, receiver);
if (result && oldValue !== value) {
trigger(target, key); // 触发更新
}
return result;
},
// 其他拦截器(如 deleteProperty 等)
});
}
const targetMap = new WeakMap(); // 存储所有响应式对象的依赖关系
function track(target, key) {
if (activeEffect) { // activeEffect 是当前正在执行的 effect
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect); // 收集当前 effect
}
}
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
const effects = depsMap.get(key);
effects && effects.forEach(effect => effect.run());
}
2. lib-flexibe 实现原理
lib-flexible
是手淘团队开发的用于解决移动端页面适配问题的库,它的核心是结合 viewport
布局和 rem
布局,下面我从几个关键方面详细说下它的实现原理。
动态设置 viewport
viewport
对于移动端页面渲染至关重要,它决定了页面如何在设备屏幕上展示。lib-flexible
会依据设备的dpr
(设备像素比)来动态设置viewport
的scale
值。dpr
反映了物理像素和逻辑像素的比例关系。比如,dpr
为 2 时,意味着一个逻辑像素对应 2 个物理像素。lib-flexible
会将viewport
的scale
值设为1 / dpr
。以dpr
为 2 为例,scale
设为0.5
,页面元素在物理像素层面就会以 2 倍大小显示,这样能保证不同dpr
设备上页面元素大小相对一致。- 通过动态修改
viewport
的scale
,可以让页面在不同设备上实现初步的适配。
基于 rem 布局
rem
是相对于根元素(<html>
)字体大小的单位。lib-flexible
会根据设备宽度动态设置<html>
元素的字体大小。- 它把设备宽度通常划分为 10 份,将
<html>
元素的字体大小设置为设备宽度的 1/10。例如,设备宽度是 750px,那么<html>
元素字体大小就是 75px,此时 1rem 就代表 75px。 - 在页面开发中,开发者使用
rem
作为元素尺寸单位,元素大小就会随着<html>
元素字体大小的变化而自适应调整,从而实现页面布局的自适应。
结合 dpr 处理细节
- 高清图片显示 :在高
dpr
设备上,为了保证图片清晰显示,lib-flexible
会根据dpr
选择合适分辨率的图片。例如dpr
为 2 时,使用 2 倍分辨率的图片,避免图片模糊。 - 1px 边框问题 :高
dpr
设备上,直接设置1px
边框会显得很粗。lib-flexible
通过缩放方式解决,在dpr
为 2 的设备上,将边框宽度设为0.5px
,在物理像素层面实现真正的 1px 边框。
不过现在 lib-flexible
逐渐被新的适配方案替代,像 vw
、vh
等单位,它们在适配方面更加简洁高效。
3. cookie、localStorage、sessionStorage 的区别
特性 | cookie | localStorage | sessionStorage |
---|---|---|---|
存储容量 | 一般约 4KB,同一域名下数量有限制 | 一般为 5MB - 10MB | 一般为 5MB - 10MB |
数据有效期 | 可设置过期时间,不设置则为会话级别,浏览器关闭即消失 | 持久化存储,手动删除才会消失 | 仅在当前会话有效,浏览器窗口关闭数据删除 |
作用域 | 同一域名下所有页面可访问,通过 path 属性可限制访问路径 | 同一域名下所有页面共享,不同域名无法访问 | 同一域名下,不同浏览器窗口或标签页(非 window.open 打开)无法共享,window.open 打开的子窗口与父窗口可共享 |
数据传输 | 每次 HTTP 请求会自动发送到服务器,增加额外开销 | 仅存储在本地,需通过 JavaScript 代码手动发送到服务器 | 仅存储在本地,需通过 JavaScript 代码手动发送到服务器 |
用途 | 身份验证、记录登录状态、跟踪用户行为等 | 存储用户配置信息、本地缓存数据等 | 临时存储当前会话中需共享的数据,如多步骤表单填写过程中的数据 |
安全性 | 易受 XSS 和 CSRF 攻击,可通过设置 HttpOnly 提高安全性 | 可能受恶意软件或社会工程学手段攻击,可加密存储数据提高安全性 | 安全性与 localStorage 类似,因生命周期短,数据泄露风险相对较小 |
4. 在哪里储存token
存储位置 | 优势 | 劣势 |
---|---|---|
Cookie | 方便在客户端和服务器间传递,设置 HttpOnly 可防 XSS 攻击 | 增加 HTTP 请求流量开销,易受 CSRF 攻击 |
LocalStorage | 存储容量大,数据持久化,便于后续会话使用 | 可被客户端脚本读取修改,有安全风险,需手动管理过期时间 |
SessionStorage | 数据仅在当前会话有效,窗口关闭自动删除,安全风险低 | 不同窗口或标签页间无法共享,不适用多窗口共享登录状态场景 |
内存 | 在应用各组件中访问快速,不受同源策略限制,页面关闭数据清除 | 应用异常崩溃或关闭时 Token 丢失,复杂应用中状态管理较复杂 |
5. 如果localstorage满了,再往里放会怎么样
当 localStorage
已满再尝试往里存储数据,浏览器通常会抛出 DOMException
异常,具体错误类型是 QuotaExceededError
。这意味着存储操作会失败,新的数据无法被成功存入 localStorage
。如果代码中没有对这个异常进行捕获处理,可能会导致程序中断执行,进而影响到相关业务功能的正常运行,比如在保存用户设置或缓存数据等场景中,数据就无法正确存储,可能造成数据丢失或业务流程中断。
为了避免这种情况,我们可以在存储数据前先通过一些方法检查 localStorage
的使用情况,例如计算已存储数据的大小与 localStorage
可用空间的比例。或者在捕获到 QuotaExceededError
异常后,采取相应的处理措施,像删除一些不常用或过期的数据来腾出空间,也可以提示用户手动清理本地存储,以保证后续数据能够正常存储。
6. token是如何加密的
首先,说明加密 token 的重要性,比如:"token 作为用户身份验证和授权的关键信息,对其进行加密是为了防止在传输和存储过程中被窃取、篡改,保障用户信息安全和系统的安全性与稳定性。"
然后,介绍常见的加密方法:
- 对称加密 :"对称加密使用相同的密钥进行加密和解密。其优点是加密和解密速度快,性能高,适用于对性能要求较高、数据传输双方可以安全共享密钥的场景。例如 AES 算法,是一种高级加密标准算法,安全性高且性能出色。在 Node.js 中可以借助
crypto
模块来使用 AES 算法加密 token。" - 非对称加密 :"非对称加密运用一对密钥,即公钥和私钥,公钥用于加密,私钥用于解密。公钥可以公开,私钥由所有者妥善保管。这种方式适用于需要保证数据传输安全性和身份验证的场景。像 RSA 算法就是广泛使用的非对称加密算法,在 Python 中可以使用
cryptography
库来实现。" - 哈希加密 :"哈希加密是将任意长度的输入通过哈希函数转换为固定长度的哈希值,是单向的,无法从哈希值反向推导出原始数据。它适用于数据完整性验证和密码存储等场景。比如 SHA - 256 算法,能生成 256 位的哈希值,在 Java 中可以使用
MessageDigest
类来实现。"
7. cookie可以设置哪些属性
Cookie 是存储在用户计算机上的小文件,用于在用户浏览网站时记录有关用户的信息。在设置 Cookie 时,除了键值对之外,还可以设置以下一些属性:
-
Expires / Max - Age
- Expires :指定 Cookie 的过期时间,是一个具体的日期和时间。当浏览器到达这个时间点时,就会自动删除该 Cookie。例如,
Expires=Wed, 10 Jun 2025 12:00:00 GMT
,表示 Cookie 将在 2025 年 6 月 10 日 12 点过期。 - Max - Age :指定 Cookie 从创建开始到过期的时长,以秒为单位。例如,
Max - Age=3600
表示 Cookie 将在 3600 秒(1 小时)后过期。如果同时设置了Expires
和Max - Age
,Max - Age
会优先于Expires
。
- Expires :指定 Cookie 的过期时间,是一个具体的日期和时间。当浏览器到达这个时间点时,就会自动删除该 Cookie。例如,
-
Domain
- 用于指定 Cookie 所属的域名。默认情况下,Cookie 仅对当前域名有效。通过设置
Domain
,可以让 Cookie 在当前域名及其子域名下都能被访问。例如,设置Domain=.example.com
,那么在www.example.com
、api.example.com
等子域名下都可以访问到该 Cookie。
- 用于指定 Cookie 所属的域名。默认情况下,Cookie 仅对当前域名有效。通过设置
-
Path
- 定义了 Cookie 在服务器上的有效路径。只有当请求的 URL 路径匹配该路径时,浏览器才会发送 Cookie。例如,设置
Path=/admin
,只有当访问/admin
路径下的页面时,浏览器才会携带该 Cookie。如果设置为Path=/
,则表示在整个域名下都有效。
- 定义了 Cookie 在服务器上的有效路径。只有当请求的 URL 路径匹配该路径时,浏览器才会发送 Cookie。例如,设置
-
Secure
- 当设置为
Secure
时,Cookie 只会在使用 HTTPS 协议的连接中被发送到服务器。这有助于防止 Cookie 在传输过程中被窃取或篡改,提高了安全性。例如,对于一些包含用户敏感信息的 Cookie,如登录凭证等,应该设置Secure
属性。
- 当设置为
-
HttpOnly
- 设置了
HttpOnly
的 Cookie 不能被客户端脚本(如 JavaScript)访问,只能通过 HTTP 协议由服务器进行读写。这可以防止跨站脚本攻击(XSS)获取用户的 Cookie 信息。例如,在登录场景中,将用户的身份验证 Cookie 设置为HttpOnly
,可以有效保护用户的登录状态。
- 设置了
-
SameSite
-
该属性用于限制第三方 Cookie,防止 CSRF(跨站请求伪造)攻击。它有三个可选值:
Strict
、Lax
和None
。Strict
:最为严格,只允许在同站请求时发送 Cookie,即只有当请求的源站和目标站完全相同时才会携带 Cookie。Lax
:相对宽松,允许在一些安全的跨站请求中发送 Cookie,例如从外部链接进入网站时的 GET 请求,但 POST 等非安全方法的跨站请求不会携带 Cookie。None
:允许跨站请求发送 Cookie,但需要同时设置Secure
属性,以确保在安全的 HTTPS 连接下进行。
-
这些属性可以根据具体的业务需求和安全要求来合理设置,以更好地管理和保护 Cookie 数据。
欢迎大家点赞关注加收藏~