极简三分钟ES6 - 代理Proxy

63 阅读1分钟

Proxy是什么

想象我们有一个房子(对象),但不想直接管理租客(操作对象)。这时你委托一个中介公司(Proxy)

  • 房东(目标对象) :原始数据
  • 中介(Proxy 实例) :拦截所有对房子的操作(读/写/删等)
  • 租客规则(Handler 对象) :定义中介如何处理租客的请求
// 创建中介公司(Proxy)
const 中介 = new Proxy(房东, {
  // 定义处理规则 
  收房租: (房东, 房客, 金额) => { /* 自定义逻辑 */ }
});

拦截对象操作

读取属性(get)

拦截对象属性的读取,并自定义返回值

const user = { name: "小明" };
const proxy = new Proxy(user, {
  get(target, prop) {
    console.log(` 有人读取了 ${prop} 属性`);
    return target[prop] || "属性不存在";
  }
});
console.log(proxy.name);   // 输出:"有人读取了 name 属性" → "小明"
console.log(proxy.age);    // 输出:"有人读取了 age 属性" → "属性不存在"

设置属性(set)

拦截属性赋值操作,可添加验证逻辑

const bank = { balance: 100 };
const proxy = new Proxy(bank, {
  set(target, prop, value) {
    if (prop === "balance" && value < 0) {
      throw new Error("余额不能为负数!");
    }
    target[prop] = value; // 通过验证才赋值
    return true; // 必须返回布尔值
  }
});
proxy.balance  = 200; // 成功 
proxy.balance  = -50; // 报错:余额不能为负数!

其他一些常用拦截操作

方法作用示例场景
deleteProperty()拦截 delete 操作防止误删关键属性 
has()拦截 in 运算符隐藏私有属性(如 _password
ownKeys()拦截 Object.keys() 等过滤敏感字段 
apply()拦截函数调用给函数调用添加日志

一些常见的使用场景

数据验证与保护 实现表单自动校验

const form = { username: "" };
const validator = new Proxy(form, {
  set(target, prop, value) {
    if (prop === "username" && value.length  < 3) {
      throw new Error("用户名至少3位!");
    }
    target[prop] = value;
    return true;
  }
});
validator.username  = "ab"; // 报错 

日志记录系统 监控对象操作轨迹

const product = { price: 100 };
const logProxy = new Proxy(product, {
  get(target, prop) {
    console.log(` 读取属性: ${prop}`);
    return target[prop];
  },
  set(target, prop, value) {
    console.log(` 设置 ${prop}${value}`);
    target[prop] = value;
    return true;
  }
});
logProxy.price  = 200; // 控制台输出:"设置 price 为 200"

私有属性保护 隐藏以下划线开头的属性

const data = { _secret: "123", public: "hello" };
const safeData = new Proxy(data, {
  has(target, prop) {
    if (prop.startsWith("_"))  return false; // 隐藏私有属性
    return prop in target;
  },
  ownKeys(target) {
    return Object.keys(target).filter(k  => !k.startsWith("_"));  
  }
});
console.log("_secret"  in safeData); // false
console.log(Object.keys(safeData));  // ["public"]

Proxy vs Object.defineProperty

特性ProxyObject.defineProperty
拦截范围13 种对象操作(全维度)仅属性读写
嵌套支持✅ 需递归实现❌ 需手动监听每个层级
数组支持✅ 直接拦截 push/pop 等❌ 需重写数组方法
兼容性ES6+ 浏览器ES5+ 浏览器

牢记

“Proxy 是对象中介,操作必经它把关:读属性(get)、改数据(set)、删字段(deleteProperty),还能隐身藏秘方(has/ownKeys)。”