Object.defineProperty:
let obj = {};
let value = 0;
Object.defineProperty(obj, "a", {
get() {
console.log("get");
return value;
},
set(newVal) {
console.log("set", newVal);
value = newVal;
}
});
obj.a; // get
obj.a = 10; // set 10
缺点:
- 只能监听具体的属性,不能直接监听整个对象。
- 不能拦截
delete、in、for...in等操作。 - 对数组、动态新增的属性支持不好。
Proxy 的基本用法
const target = { name: "wenlong", age: 18 };
const proxy = new Proxy(target, {
get(obj, prop) {
console.log("拦截 get:", prop);
return obj[prop];
},
set(obj, prop, value) {
console.log("拦截 set:", prop, value);
obj[prop] = value;
return true; // 必须返回 true,否则会报错
},
deleteProperty(obj, prop) {
console.log("拦截 delete:", prop);
return delete obj[prop];
}
});
console.log(proxy.name); // 拦截 get: name
proxy.age = 20; // 拦截 set: age 20
delete proxy.name; // 拦截 delete: name
Proxy 原理就是在对象和外部访问之间加了一层“拦截代理”,所有操作都会先进入 trap,由你决定放行、修改还是拒绝。
Proxy实现深度监听
Proxy 本身只会对被代理的对象那一层生效,如果属性里还有对象,它不会自动“递归”下去。
function deepProxy(target, handler) {
if (typeof target !== "object" || target === null) return target;
return new Proxy(target, {
get(obj, prop, receiver) {
const value = Reflect.get(obj, prop, receiver);
// 如果是对象,递归代理
return deepProxy(value, handler);
},
set(obj, prop, value, receiver) {
const old = obj[prop];
const result = Reflect.set(obj, prop, value, receiver);
handler(obj, prop, value, old); // 自定义回调
return result;
}
});
}
// 使用
const obj = {
user: {
name: "wenlong",
age: 18
},
list: [1, 2, 3]
};
const proxy = deepProxy(obj, (obj, key, value, old) => {
console.log(`属性 ${String(key)} 从 ${old} 改为 ${value}`);
});
proxy.user.age = 20; // ✅ 属性 age 从 18 改为 20
proxy.list.push(4); // ✅ 属性 3 从 undefined 改为 4
Vue3 的 reactive 就是基于 Proxy 深度代理的,但它做了两点优化:
- 懒代理(lazy observe):只在你访问到某个对象属性时,才去递归包裹,而不是一开始就全量递归。
- 缓存:同一个对象不会被代理多次,使用
WeakMap做缓存。
rem原理
📌 1. 普通 em 与 rem 的区别
-
em:相对于当前元素的
font-size。- 如果父元素
font-size: 20px,子元素设置width: 2em→ 就是40px。 - 有层级嵌套时,
em会不断累积,容易出现“继承叠加效应”。
- 如果父元素
-
rem:始终相对于根元素
<html>的font-size,不会受父元素影响。- 如果
html { font-size: 16px },无论嵌套多少层,1rem = 16px。
- 如果
📌 2. 浏览器如何计算 rem
-
浏览器解析 CSS 时,先找到
<html>的font-size值(默认一般是16px)。 -
遇到
rem单位时,用这个值来换算:1rem = html 的 font-size2.5rem = 2.5 × html 的 font-size
📌 3. 响应式设计常见用法
利用 rem + JS 动态设置 <html> 的 font-size,就能实现自适应布局:
html {
font-size: 16px; /* 基准值 */
}
.container {
width: 20rem; /* 等于 20 × 16px = 320px */
}
再配合 JS:
// 根据屏幕宽度设置 html 字号(常见移动端适配方案)
function setRem() {
const baseSize = 16;
const scale = document.documentElement.clientWidth / 375; // 以 iPhone 375px 设计稿为基准
document.documentElement.style.fontSize = baseSize * scale + 'px';
}
window.onresize = setRem;
setRem();
这样写后,1rem 就会随屏幕宽度缩放,所有用 rem 定义的元素都会等比适配。
📌 4. rem 的优点
- 避免
em的继承陷阱。 - 统一的缩放基准,便于响应式布局。
- 用户修改浏览器默认字体大小时,页面能自动适配,提升可访问性。
🔑 HTTP 和 HTTPS 的区别
主要区别
| 对比点 | HTTP | HTTPS |
|---|---|---|
| 传输安全 | 明文传输,容易被窃听、篡改、中间人攻击 | 加密传输,数据通过 TLS/SSL 加密,安全性高 |
| 端口 | 默认 80 | 默认 443 |
| 证书 | 不需要 | 需要 SSL/TLS 证书(由 CA 颁发) |
| 速度 | 相对快,因为无加密解密过程 | 稍慢,因为有握手、加密解密(但现在硬件性能强,几乎无感) |
| SEO | 无优势 | 搜索引擎更偏好 HTTPS,Google 等会优先收录 |
| 浏览器提示 | 会显示“不安全” | 有安全锁 🔒 |
🔨 实现“比 1px 更细的线”的方法
利用 transform scale 缩放
.divider {
height: 1px;
background: #000;
transform: scaleY(0.5); /* 压缩到 0.5px */
transform-origin: 0 0;
}
伪元素 + transform
.divider::after {
content: "";
display: block;
height: 1px;
background: #000;
transform: scaleY(0.25); /* 视觉上 0.25px */
}
SVG 或 Canvas