看完这篇文章,你就知道什么是proxy

22 阅读4分钟

一、Proxy 是什么?

Proxy(代理)是ES6引入的一个强大的特性,它允许我们拦截并自定义对象的基本操作。简单来说,Proxy就像一个“中间人”,控制对目标对象的访问。你可以通过它监控对象的属性读取、赋值、删除等操作,并在这些操作发生时插入自定义逻辑。

通俗的来讲就是想象一下你有一个朋友叫“小代”,你想找某个人办事,但这个人不直接见你。你只能通过“小代”去传达你的请求,小代会帮你和那个人打交道。

在这个场景中:

  • 那个“被你找的人”就是目标对象(target)
  • “小代”就是 Proxy(代理)
  • 你要做的事情(比如:问问题、改东西、删东西),都要经过“小代”

所以,Proxy 就是一个中间人,你可以通过它来控制对某个对象的操作。


二、Proxy 的基本结构

const proxy = new Proxy(target, handler);
  • target:你要代理的对象。
  • handler:一个配置对象,里面定义了“你想在什么时候做点什么事情”。

三、举个最简单的例子:监控属性访问

我们想监控谁在读取或修改对象的属性。

const obj = {
  name: "张三",
  age: 20
};

const handler = {
  get(target, key) {
    console.log("有人要读取属性:" + key);
    return target[key];
  },
  set(target, key, value) {
    console.log("有人要设置属性:" + key + " 为 " + value);
    target[key] = value;
    return true; // 必须返回 true 表示设置成功
  }
};

const p = new Proxy(obj, handler);

console.log(p.name);   // 输出:有人要读取属性:name
p.age = 30;            // 输出:有人要设置属性:age 为 30

解释一下这段代码:

  • 我们创建了一个 Proxy 对象 p
  • 每次读取属性(如 p.name)都会触发 get 方法
  • 每次设置属性(如 p.age = 30)都会触发 set 方法
  • 这样我们就知道了谁在操作对象的哪些属性!

拦截器(handler)常用方法一览

get(target, key)读取属性obj.name
set(target, key, value)设置属性obj.name = 'Tom'
has(target, key)in 运算符'name' in obj
deleteProperty(target, key)delete 操作delete obj.name
apply(target, thisArg, args)函数调用fn()fn.apply()
construct(target, args)new 调用new MyClass()

四、实际应用场景(通俗举例)

场景1:数据验证(防止乱改)

比如你希望别人不能随便把年龄改成字符串:

const user = {
  age: 18
};

const handler = {
  set(target, key, value) {
    if (key === 'age' && typeof value !== 'number') {
      console.error('年龄必须是数字!');
      return true; // 不抛错,只是阻止赋值
    }
    target[key] = value;
    return true;
  }
};

const proxy = new Proxy(user, handler);

proxy.age = "abc"; // 输出:年龄必须是数字!
proxy.age = 25;    // 正常执行

场景2:权限控制(有些属性不能看)

比如某些私有属性不能让别人看到:

const data = {
  username: "admin",
  _password: "123456"
};

const handler = {
  get(target, key) {
    if (key.startsWith('_')) {
      throw new Error("不能访问私有属性");
    }
    return target[key];
  }
};

const proxy = new Proxy(data, handler);

console.log(proxy.username);     // 正常输出 admin
console.log(proxy._password);    // 报错:不能访问私有属性

场景3:响应式系统(Vue3的核心原理)

Vue3用Proxy来监听数据变化,自动更新页面。

比如你改了数据,页面就自动刷新了:

let data = {
  count: 0
};

const handler = {
  set(target, key, value) {
    console.log("数据变了,准备更新视图!");
    target[key] = value;
    return true;
  }
};

const proxy = new Proxy(data, handler);

proxy.count++; // 输出:数据变了,准备更新视图!

五、常见面试题 & 答案

Q1:Proxy 是干什么的?

答:Proxy 是用来拦截并自定义对象行为的一种机制。就像一个“中间人”,我们可以在这个中间人里加一些逻辑,比如打印日志、校验数据、权限控制等。


Q2:Proxy 和 Object.defineProperty 有什么区别?

区别ProxyObject.defineProperty
支持数组×
新增属性是否能监听×
拦截操作种类多(13种)少(只有get/set)
兼容性ES6+ES5+

Q3:Reflect 是干嘛的?为什么要和 Proxy 一起用?

答:Reflect 提供了一些默认操作的方法,比如 Reflect.get()、Reflect.set(),这样我们在 Proxy 中调用它们时可以更安全、统一,并且兼容性更好。


六、总结一句话

Proxy 就像一个“门卫”,你想访问一个对象的属性或者修改它,都得先过它这一关。

你可以利用这个“门卫”来做很多事,比如:

  • 监控谁动了对象
  • 控制谁能看到什么
  • 防止错误的数据进来
  • 实现 Vue 那样的响应式系统

七、练习建议

你可以试着写几个简单的 Proxy:

  1. 拦截删除操作,让用户确认后再删除。
  2. 创建一个只读对象,不让别人修改。
  3. 统计某个对象被访问了多少次。