💘一个真实又扎心的故事
假设你叫“郑志鹏”,看上了公司里温柔漂亮的“小美”。你想表达爱意,于是决定送她一束花。
javascript
编辑
let zzp = {
name: '郑志鹏',
sendFlower: function(target) {
target.receiveFlower(this);
}
};
let xm = {
name: '小美',
xq: 30, // 心情指数,初始值很低
receiveFlower: function(sender) {
console.log(`小美收到了${sender.name}的花`);
if (this.xq < 80) {
console.log('不约,我们不约!');
} else {
console.log('硕果走一波!!!');
}
}
};
你兴冲冲地执行:
javascript
编辑
zzp.sendFlower(xm);
// 输出:
// 小美收到了郑志鹏的花
// 不约,我们不约!
💔结果很现实:被拒了。
为什么?因为你直接送花,而她心情值只有30,根本没准备好接受感情。
🧠 换个思路:找个“情感代理”
这时候,你的好朋友“小红”出现了。她和小美是闺蜜,了解她的脾气。你决定让小红先帮你“暖场”。
于是你把花送给小红,由她来决定什么时候转交给小美。
这,就是**代理模式(Proxy Pattern)**的核心思想!
🎯 什么是代理模式?
代理模式(Proxy Pattern) 为其他对象提供一种代理以控制对这个对象的访问。
通俗地说:
你不直接操作目标对象,而是通过一个“中间人”来间接操作它。这个中间人可以做预处理、过滤、延迟加载、权限控制等。
✅ 核心特征:
- 代理对象和目标对象实现相同的接口
- 客户端无需知道使用的是真实对象还是代理
- 代理可以在调用前后增加额外逻辑
🌱 代码实现:小红成为“情感代理”
我们让小红(xh)也实现 receiveFlower 方法,并在适当时机再调用小美的方法:
javascript
编辑
let xh = {
name: '小红',
receiveFlower: function(sender) {
console.log(`小红代收了${sender.name}送的花`);
// 模拟感情升温过程:3秒后心情值达标
setTimeout(() => {
console.log('小红悄悄对小美说:这人还不错...');
xm.xq = 90; // 心情值拉满
xm.receiveFlower(sender); // 转交花束
}, 3000);
}
};
现在你还是调用 sendFlower,但目标换成了小红:
javascript
编辑
zzp.sendFlower(xh);
// 输出:
// 小红代收了郑志鹏送的花
// (3秒后)
// 小美收到了郑志鹏的花
// 硕果走一波!!!
🎉 成功了!虽然花最终还是给了小美,但因为有了“代理”,结果完全不同。
🔍 代理模式的三大优势
| 优势 | 说明 | 对应案例 |
|---|---|---|
| 控制访问 | 防止直接调用目标对象 | 小美心情差时不接受表白 |
| 增强功能 | 在调用前后添加逻辑 | 小红帮忙提升好感度 |
| 延迟加载 | 等条件满足后再执行 | 3秒后才真正送花 |
🛠 实际开发中的代理模式应用
1️⃣ 图片懒加载(Lazy Load)
javascript
编辑
function ImageProxy(url) {
const img = new Image();
const placeholder = document.createElement('img');
placeholder.src = 'loading.gif';
// 先显示loading图
document.body.appendChild(placeholder);
// 异步加载真实图片
img.onload = function() {
placeholder.replaceWith(img);
};
img.src = url;
}
👉 这里的 placeholder 就是真实图片的代理。
2️⃣ 防抖代理(Debounced API Call)
javascript
编辑
function debounceProxy(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 使用
const searchAPI = () => console.log('发起搜索请求');
const debouncedSearch = debounceProxy(searchAPI, 500);
👉 用户频繁输入时,只有最后一次触发真实请求。
3️⃣ Vue 3 的 Proxy 响应式系统
javascript
编辑
const data = { count: 0 };
const reactiveData = new Proxy(data, {
set(target, key, value) {
console.log(`属性 ${key} 被修改为 ${value}`);
// 触发视图更新...
return Reflect.set(target, key, value);
}
});
reactiveData.count = 1;
// 输出:属性 count 被修改为 1
👉 Vue 3 用 Proxy 拦截对象操作,实现数据响应式。
🧩 代理模式 vs 装饰器模式 vs 中介者模式
| 模式 | 目的 | 区别 |
|---|---|---|
| 代理模式 | 控制访问 | 强调“代替”和“权限控制” |
| 装饰器模式 | 动态添加功能 | 强调“功能叠加” |
| 中介者模式 | 解耦多个对象通信 | 多对多 → 一对多 |
⚠️ 代理模式通常一对一,只为一个目标服务。
✅ 何时使用代理模式?
- 需要延迟初始化(懒加载)
- 需要权限校验或访问控制
- 需要日志记录、性能监控
- 需要网络请求缓存
- 需要远程对象本地化(如RPC)
🎯 总结:爱情与代码的共通哲学
通过这个“送花”的例子,我们不仅学会了代理模式,更明白了一个道理:
有时候,直接不是最好的方式。
在感情中,你需要一个“中间人”帮你铺垫; 在编程中,你需要一个“代理”帮你控制访问。
代理模式的本质,是优雅地介入过程,智能地控制结果。
📚 一句话记住代理模式
“我能帮你收花,但我不是花的归宿——我只是通往幸福的桥梁。”
🙋♂️ 互动时间
你觉得还有哪些生活场景可以用代理模式解释?
评论区留下你的想法,点赞最高的送《JavaScript设计模式》电子书一本!
📌 关注我,下周带你用“点外卖”讲清楚观察者模式(Observer Pattern) !
#设计模式 #前端开发 #JavaScript #Proxy #编程思维 #程序员情感 #掘金好文