原理深层次面试题

69 阅读3分钟

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

缺点:

  • 只能监听具体的属性,不能直接监听整个对象。
  • 不能拦截 deleteinfor...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 深度代理的,但它做了两点优化:

  1. 懒代理(lazy observe):只在你访问到某个对象属性时,才去递归包裹,而不是一开始就全量递归。
  2. 缓存:同一个对象不会被代理多次,使用 WeakMap 做缓存。

rem原理

📌 1. 普通 emrem 的区别

  • em:相对于当前元素的 font-size

    • 如果父元素 font-size: 20px,子元素设置 width: 2em → 就是 40px
    • 有层级嵌套时,em 会不断累积,容易出现“继承叠加效应”。
  • rem:始终相对于根元素 <html>font-size,不会受父元素影响。

    • 如果 html { font-size: 16px },无论嵌套多少层,1rem = 16px

📌 2. 浏览器如何计算 rem

  1. 浏览器解析 CSS 时,先找到 <html>font-size 值(默认一般是 16px)。

  2. 遇到 rem 单位时,用这个值来换算:

    • 1rem = html 的 font-size
    • 2.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 的区别

主要区别

对比点HTTPHTTPS
传输安全明文传输,容易被窃听、篡改、中间人攻击加密传输,数据通过 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