🌸 从“送花”说起:JavaScript 中的代理模式实战详解

140 阅读4分钟

标签:JavaScript、设计模式、代理模式、前端进阶

在编程世界里,设计模式是前人总结出的“最佳实践”。今天,我们不讲枯燥的理论,而是通过一个浪漫又有趣的场景——“送花”,来深入理解 JavaScript 中的 代理模式(Proxy Pattern)

我们将用一个“肖楚南追小美”的故事,带你掌握代理模式的核心思想,并结合你熟悉的 对象字面量函数异步 等知识,写出更优雅、可维护的代码。


🌱 故事背景:送花的烦恼

假设我们有这样一个场景:

let xcNan = {
  name: '肖楚南',
  hobbies: ['学习', '乒乓球'],
  sendFlower: function(target) {
    target.receiveFlower(xcNan);
  }
};

let xm = {
  xq: 30, // 心情值
  name: '小美',
  receiveFlower: function(sender) {
    console.log('小美收到了花', sender.name + '送的花');
    if (this.xq < 80) {
      console.log('不约,我们不约');
    } else {
      console.log('硕果走一波!!!');
    }
  }
};

现在,肖楚南想给小美送花,于是他直接调用:

xcNan.sendFlower(xm);
// 输出:小美收到了花 肖楚南送的花
//      不约,我们不约

结果很惨淡,因为小美心情值只有 30,根本不想理他。


🤔 问题来了:能不能“代理”送花?

肖楚南很苦恼:我直接送花,小美不理我。有没有人能帮我“代理”一下,先提升她的心情,再送花?

这时,代理模式就派上用场了!

✅ 什么是代理模式?

代理模式(Proxy Pattern) :为一个对象提供一个替身,以控制对原对象的访问。代理对象在客户端和目标对象之间起到中介作用。

在我们这个场景中:

  • 目标对象:小美(xm
  • 客户端:肖楚南(xcNan
  • 代理对象:小红(xh)——她可以先“调节气氛”,再帮肖楚南送花。

💡 用“小红”实现代理模式

我们让小红作为“情感代理”,她在收到花后,先等 3 秒钟(模拟调节气氛),把小美心情值提升到 90,再帮肖楚南送花:

let xh = {
  name: '小红',
  receiveFlower: function(sender) {
    console.log('小红收到了', sender.name + '送的花');

    // 代理逻辑:先提升小美心情
    setTimeout(() => {
      xm.xq = 90;
      console.log('小红:我已经把小美心情调到90了!');
      // 代理执行:帮肖楚南完成送花
      xm.receiveFlower(sender);
    }, 3000);
  }
};

现在,肖楚南不再直接送花给小美,而是送给小红(代理):

xcNan.sendFlower(xh); // 注意:这里传的是 xh,不是 xm

输出结果:

小红收到了 肖楚南送的花
(等待3秒...)
小红:我已经把小美心情调到90了!
小美收到了花 肖楚南送的花
硕果走一波!!!

🎉 成功了!通过“代理”,肖楚南终于打动了小美。


🔍 代理模式的核心优势

  1. 控制访问:不直接暴露目标对象(小美),而是通过代理(小红)进行访问。
  2. 增强功能:代理可以在真正操作前/后添加额外逻辑(如延时、验证、缓存等)。
  3. 解耦:发送者(肖楚南)不需要知道“如何提升心情”,只需关心“送花”这个动作。

🛠️ 更优雅的写法:使用 ES6 Proxy

JavaScript 提供了原生的 Proxy 对象,可以更灵活地实现代理模式。

我们可以用 Proxy 来代理“小美”的 receiveFlower 方法:

let xmProxy = new Proxy(xm, {
  get(target, property) {
    if (property === 'receiveFlower') {
      return function(sender) {
        console.log(`【代理拦截】${sender.name} 想给小美送花`);
        setTimeout(() => {
          xm.xq = 90; // 提升心情
          console.log('心情已提升至90!');
          target.receiveFlower(sender);
        }, 2000);
      };
    }
    return target[property];
  }
});

现在,肖楚南可以直接“送花”给代理对象:

xcNan.sendFlower(xmProxy);

输出:

【代理拦截】肖楚南 想给小美送花
(等待2秒...)
心情已提升至90!
小美收到了花 肖楚南送的花
硕果走一波!!!

✅ 这就是 Proxy 的强大之处:无需修改原对象,就能拦截和增强其行为。


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

场景说明
图片懒加载Proxy 控制图片加载时机
权限控制代理用户操作,检查权限后再执行
缓存代理代理函数调用,缓存结果避免重复计算
日志记录代理方法调用,自动记录日志
防抖/节流代理事件处理函数,控制触发频率

📌 总结

通过“送花”这个生活化场景,我们理解了:

  • 代理模式的核心是 “用代理对象代替真实对象”
  • 代理可以在不修改原对象的前提下,增强功能、控制访问
  • JavaScript 的 Proxy 是实现代理模式的利器
  • 设计模式不是“炫技”,而是为了解决实际问题

💬 编程如人生,有时候直接追求未必成功,找个“代理”迂回一下,反而柳暗花明。


🎁 课后思考

  1. 如果小红自己也喜欢肖楚南,她会不会“截胡”送花?如何用代理模式实现“情感竞争”?
  2. 能否用 Proxy 实现一个“防抖代理”,避免频繁送花?

欢迎在评论区留下你的想法!