news 2026/4/28 21:40:34

前端八股2---Proxy 代理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
前端八股2---Proxy 代理

目录

  • 一、核心概念
  • 基础语法
  • 二、核心结构
  • 三、Vue3 中的应用
  • 3.1 响应式系统
  • 3.2 间接使用 Proxy 的场景
  • 四、Vue2 vs Vue3 对比(面试常考)
  • 五、Proxy 能拦截的操作(响应式相关)
  • 六、ES 规范版本
  • 七、面试高频题
  • Q1:Vue3 为什么不兼容 IE?
  • Q2:Proxy 和 Object.defineProperty 的区别?
  • Q3:Vue3 的响应式为什么比 Vue2 快?
  • Q4:Vue3 的 reactive 是深度响应式吗?
  • Q5:Vue3 的响应式原理是什么?
  • Q6:用 Proxy 实现一个简单的数据校验
  • Q7:Proxy 能代理多层嵌套对象吗?
  • Q8:用 Proxy 实现一个访问日志记录器
  • Q9:Proxy 代理后的对象和原对象有什么关系?
  • Q10:Reflect 是什么?有什么作用?
  • Q11:为什么 Proxy 中要使用 Reflect?

一、核心概念

Proxy 就是给对象套一层代理,拦截所有操作,实现监听、控制、增强。

给对象、数组、函数包一层"拦截层",你对目标做任何操作(读、改、删、调用…),都会先经过这层代理,你可以拦截、修改、监听。

基础语法

const target = { name: "张三" }; const proxy = new Proxy(target, { // 拦截读取属性 get(target, prop) { console.log("读取了:" + prop); return target[prop]; }, // 拦截修改属性 set(target, prop, value) { console.log("修改了:" + prop); target[prop] = value; return true; // 必须返回 true 表示成功 } }); proxy.name; // 打印:读取了:name proxy.name = "李四"; // 打印:修改了:name

二、核心结构

new Proxy(目标对象, { get(target, prop, receiver) {}, // 读取属性 set(target, prop, value, receiver) {}, // 修改属性 deleteProperty(target, prop) {}, // 删除属性 has(target, prop) {}, // in 操作符 apply(target, thisArg, args) {}, // 函数调用 construct(target, args) {}, // new 操作符 ownKeys(target) {}, // Object.getOwnPropertyNames defineProperty(target, prop, desc) {}, // 定义新属性 // ... 还有很多 })

三、Vue3 中的应用

3.1 响应式系统

Vue3 的reactive/ref底层就是Proxy

import { reactive } from 'vue' const state = reactive({ name: 'zs' }) // 这个 state 本质就是一个 Proxy 对象

作用机制:

  • 拦截state.name的读取 →收集依赖

  • 拦截state.name = xxx的修改 →触发更新

3.2 间接使用 Proxy 的场景

只要用了以下 API,底层都在使用 Proxy:

  • reactive()

  • ref()

  • computed()

  • defineProps/defineEmits(内部有代理)

  • 组件实例this(被代理过的)

它们都内置了依赖收集 + 派发更新


四、Vue2 vs Vue3 对比(面试常考)

对比项Vue2 (Object.defineProperty)Vue3 (Proxy)
新增属性❌ 监听不到(需要$set✅ 能监听到
删除属性❌ 监听不到(需要$delete✅ 能监听到
数组下标修改❌ 监听不到✅ 能监听到
数组 length 修改❌ 监听不到✅ 能监听到
数组方法 (push/pop等)⚠️ 需要拦截重写✅ 天然拦截
性能需要递归遍历所有属性懒代理,按需拦截

Vue2 缺陷总结:

  • 监听不全面,很多情况监听不到

  • 必须用额外 API($set$delete)补救

Vue3 优势总结:

  • 能监听:新增、删除、数组修改

  • 性能更好、功能更强


五、Proxy 能拦截的操作(响应式相关)

拦截器对应操作响应式用途
get读取属性收集依赖
set修改已有属性触发更新
deleteProperty删除属性触发更新
defineProperty新增属性触发更新
数组方法push/pop/shift触发更新

六、ES 规范版本

特性版本
PromiseES6 (ES2015)
ProxyES6 (ES2015)
async/awaitES2017

⚠️注意纠正:Proxy 是 ES6(ES2015)的一部分,不是 ES2016。
只是浏览器支持较晚(Chrome 49,2016年3月),导致很多人误以为版本更晚。


七、面试高频题

Q1:Vue3 为什么不兼容 IE?

A:因为 Vue3 底层用了Proxy实现响应式,而 Proxy:

  • 没有 polyfill(无法用纯 JS 模拟)

  • IE 全系列不支持


Q2:Proxy 和 Object.defineProperty 的区别?

A:

  1. 监听范围:Proxy 可监听增/删/数组操作,defineProperty 不行

  2. 性能:Proxy 是懒代理(按需),defineProperty 需要递归遍历

  3. 语法:Proxy 拦截操作更统一,defineProperty 需要单独定义 getter/setter


Q3:Vue3 的响应式为什么比 Vue2 快?

回答要点:

  1. 懒代理:不用递归遍历所有嵌套对象,初始化更快

  2. 按需拦截:只代理访问到的对象,内存占用更少

  3. Proxy 本身性能:比 defineProperty 的 getter/setter 机制更高效

懒代理 = 不在一开始就代理所有嵌套对象,而是等真正访问到某个属性时,才对该属性的值(如果是对象)进行代理。


Q4:Vue3 的 reactive 是深度响应式吗?

回答:

是的,但它是通过懒代理实现的深度响应式。
一开始只代理最外层,当访问到嵌套对象时,才递归创建代理。
最终效果和 Vue2 一样是深度响应式,但性能和内存都更好。


Q5:Vue3 的响应式原理是什么?

回答模板:

Vue3 的响应式基于 Proxy 实现。通过reactive函数给数据创建 Proxy 代理,在get拦截中收集依赖(哪些组件在用这个数据),在setdeleteProperty等拦截中触发更新(通知组件重新渲染)。同时采用懒代理策略,只在访问到嵌套对象时才递归代理,提升性能。

// 简化版原理 function reactive(target) { return new Proxy(target, { get(target, key, receiver) { const res = Reflect.get(target, key, receiver); track(target, key); // 收集依赖 return res; }, set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver); trigger(target, key); // 触发更新 return result; } }); }

Q6:用 Proxy 实现一个简单的数据校验

function createValidator(obj, validator) { return new Proxy(obj, { set(target, key, value) { if (validator[key] && !validator[key](value)) { throw new Error(`${key} 校验失败:${value} 不合法`); } target[key] = value; return true; } }); } const user = createValidator( { age: 0 }, { age: (val) => val >= 0 && val <= 150 } ); user.age = 25; // ✅ 成功 user.age = -10; // ❌ 报错:age 校验失败

Q7:Proxy 能代理多层嵌套对象吗?

Proxy 默认只代理第一层。要实现深度响应式,需要在get拦截中判断返回值是否是对象,如果是,则递归调用reactive进行代理。这就是 Vue3 的懒代理策略。

function reactive(target) { return new Proxy(target, { get(target, key, receiver) { const res = Reflect.get(target, key, receiver); // 关键:如果是对象,递归代理 if (res !== null && typeof res === 'object') { return reactive(res); } return res; } }); }
  1. reactive 内部有懒代理吗?✅ 有,这是它的核心特性

  2. ref 和 reactive 是 Vue 3 的吗?✅ 是的,都是 Vue 3 Composition API 的核心


Q8:用 Proxy 实现一个访问日志记录器

function createLogger(obj) { return new Proxy(obj, { get(target, key) { console.log(`[${new Date().toLocaleTimeString()}] 读取了 ${String(key)}`); return target[key]; }, set(target, key, value) { console.log(`[${new Date().toLocaleTimeString()}] 修改了 ${String(key)} = ${value}`); target[key] = value; return true; } }); } const data = createLogger({ name: '张三' }); data.name; // 记录读取日志 data.name = '李四'; // 记录修改日志

Q9:Proxy 代理后的对象和原对象有什么关系?

代理对象和原对象是两个不同的对象。修改代理对象会影响原对象(因为代理内部操作的是原对象),但直接修改原对象不会触发代理的拦截。所以在 Vue3 中应该始终使用代理对象进行操作。

const obj = { name: '张三' }; const proxy = new Proxy(obj, { set(target, key, value) { console.log('set 拦截'); target[key] = value; return true; } }); proxy.name = '李四'; // 触发拦截 ✅ obj.name = '王五'; // 不触发拦截 ❌

Q10:Reflect 是什么?有什么作用?

答:Reflect 是 ES6 新增的内置对象,提供了一套与 Proxy 拦截器一一对应的方法。主要作用:

  1. 与 Proxy 配合,保证 this 指向正确

  2. 提供统一的返回值(boolean),便于错误处理

  3. 将对象操作函数化,更加规范


Q11:为什么 Proxy 中要使用 Reflect?

答:主要有两个原因:

  1. 保证 this 正确Reflect.getreceiver参数会作为 getter 中的 this 指向,这在处理原型链时至关重要

  2. 执行默认行为:Proxy 拦截后,通常还需要执行对象的默认操作,Reflect 提供了标准的默认实现

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 9:09:56

AUBO i5 与 ROS 网络联调实战:打通 MoveIt! 控制真实机械臂的最后一公里

1. 环境准备&#xff1a;搭建AUBO i5与ROS的通信桥梁 第一次把MoveIt!的运动规划算法应用到真实机械臂上时&#xff0c;那种兴奋感我至今记得。但很快就被网络配置问题浇了盆冷水——虚拟世界的指令怎么都传不到真实的AUBO i5上。后来才发现&#xff0c;网络配置就像给两个说不…

作者头像 李华
网站建设 2026/4/16 13:04:32

MIT6.S081 Lab3通关秘籍:手把手教你实现进程专属内核页表(附完整代码)

MIT6.S081 Lab3深度实战&#xff1a;从零构建进程专属内核页表 在操作系统的核心机制中&#xff0c;内存管理始终是最具挑战性的部分之一。MIT6.S081的Lab3实验将带领我们深入xv6内核&#xff0c;完成从单一内核页表到进程独立内核页表的架构升级。这个实验不仅关乎理论理解&am…

作者头像 李华
网站建设 2026/4/17 9:05:39

解决React Native Expo中Firebase存储权限问题

在开发React Native应用程序时,结合Explo和Firebase是一个常见的选择,尤其是在处理用户上传功能如头像上传时。然而,常常会遇到一些棘手的权限问题。下面我将详细介绍如何解决在使用Expo ImagePicker和Firebase Storage时遇到的权限问题,并提供一个实际的解决方案。 问题背…

作者头像 李华
网站建设 2026/4/15 16:34:57

论文洞察:面向RAG场景的KV Cache复用技术兰心兰心

研究背景 本文基于芝加哥大学、香港中文大学、微软在EuroSys25上发表的研究成果《CacheBlend: Fast Large Language Model Serving for RAG with Cached Knowledge Fusion》进行深入分析。 CacheBlend是面向RAG场景的LLM推理加速方案&#xff0c;解决了多文本块输入下KV Cach…

作者头像 李华