《JavaScript 代理模式入门:用 Proxy 写出更优雅的代码》

5 阅读3分钟

JavaScript 代理模式入门:用 Proxy 写出更优雅的代码

本文适合前端初学者和想巩固设计模式的开发者。通过生活化例子 + 可运行代码,轻松掌握 JS 代理模式的核心思想与实战用法。

在日常开发中,你是否遇到过这些需求?

  • 想在调用某个函数前加权限校验?
  • 希望自动记录用户操作日志?
  • 需要缓存计算结果避免重复开销?

其实,这些问题都可以用一个经典设计模式来优雅解决 —— 代理模式(Proxy Pattern)

今天,我们就用最简单的方式,带你彻底搞懂它!


🤔 什么是代理模式?

代理模式 是一种结构型设计模式,它的核心思想是:

不直接访问目标对象,而是通过一个“代理对象”来间接控制对它的访问。

你可以把代理想象成“中间人”:

  • 它和真实对象有相同的接口;
  • 它可以在转发请求前后,加入额外逻辑;
  • 真实对象无需知道代理的存在。

💡 生活中的例子:送花代理人

假设你想给朋友 xm 送花,但他不在家。于是你找了一个共同好友 xh 帮忙转交。

你 → xh(代理)→ xm(真实对象)
  • xhxm 都能“收花”(接口一致);
  • xh 在转交前可以说一句:“这是小明送的!”;
  • 你只和 xh 打交道,完全不用关心 xm 是否在家。

这就是代理模式的精髓:解耦 + 增强


🧩 JavaScript 如何实现代理?

方法一:使用 ES6 原生 Proxy(推荐 ✅)

// 真实对象
const xm = {
  receiveFlower(name) {
    console.log(`${name} 收到了花`);
  }
};

// 创建代理
const xh = new Proxy(xm, {
  get(target, prop) {
    if (prop === 'receiveFlower') {
      return (...args) => {
        console.log('✨ 正在送花...');
        target.receiveFlower(...args);
        console.log('✅ 花已送达!');
      };
    }
    return target[prop];
  }
});

// 使用代理
xh.receiveFlower('小明');
// 输出:
// ✨ 正在送花...
// 小明 收到了花
// ✅ 花已送达!

⚠️ 注意:Proxy 拦截的是属性访问,所以要用 get 拦截方法调用。


方法二:手动模拟代理(兼容旧环境)

如果你需要支持不支持 Proxy 的老浏览器,也可以手动封装:

const xm = {
  receiveFlower(name) {
    console.log(`${name} 收到了花`);
  }
};

const xh = {
  receiveFlower(name) {
    console.log('✨ 正在送花...');
    xm.receiveFlower(name);
    console.log('✅ 花已送达!');
  }
};

xh.receiveFlower('小红');

虽然不够灵活,但在简单场景下完全够用。


🎯 代理模式的常见应用场景

场景实现思路
🔐 权限控制代理检查用户角色,再决定是否调用真实方法
📝 日志记录在调用前后打印日志,用于调试或埋点
🔄 缓存代理第一次计算后缓存结果,后续直接返回
🚀 懒加载图片/数据首次访问时才加载,提升性能
🛡️ 校验输入代理先验证参数合法性,再传给真实对象

✅ 总结一句话

代理模式 = 用一个“中间人”控制对真实对象的访问,在不修改原对象的前提下,增强功能、提高安全性。


🚀 动手试试!

学完不如练一练,试试完成以下小任务:

  1. 日志代理:写一个代理,记录每次调用函数的名称和参数;
  2. 缓存代理:实现一个 fibProxy,缓存斐波那契数列的计算结果;
  3. 只读代理:用 Proxy 创建一个不可修改的对象(拦截 set 操作)。
// 示例:只读代理
const readOnly = (obj) => new Proxy(obj, {
  set() {
    throw new Error('该对象是只读的!');
  }
});

📚 延伸阅读

  • MDN - Proxy
  • 《JavaScript 设计模式与开发实践》—— 曾探