Logo
Section 1 / 19

理解代理模式

使用 JavaScript 的 Proxy 在运行时拦截和修改对象交互,让你能够在不修改原始代码的情况下添加控制、延迟求值或数据转换。

导入

理解代理模式

使用 JavaScript 的 Proxy 在运行时拦截和修改对象交互,让你能够在不修改原始代码的情况下添加控制、延迟求值或数据转换。

...
The Proxy Pattern intercepts object access to control or modify behavior at runtime

代理定义了与对象交互的行为,而非对象包含的内容

1// 步骤 1:从一个真实对象(目标)开始 2const target = { ... }; 3 4// 步骤 2:定义一个处理器,描述在访问或修改目标时应执行的操作 5const handler = { 6 // 当有人读取属性时: 7 get(...) { 8 // 执行任何额外行为(例如,记录、验证、转换) 9 // 然后将读取操作转发给真实对象 10 }, 11 12 // 当有人写入属性时: 13 set(...) { 14 // 可能检查权限或修改值 15 // 然后更新真实对象 16 } 17 18 // ... 19}; 20 21// 步骤 3:创建连接两者的代理 22const proxy = new Proxy(target, handler); 23 24// 步骤 4:像使用原始对象一样使用代理

Node.js

1// 重型服务模拟 2class DataService { 3 constructor() { 4 console.log('Initializing heavy DataService...'); 5 this.data = { secret: 'classified', public: 'hello' }; 6 } 7 8 fetch(key) { 9 return this.data[key]; 10 } 11} 12 13// 代理工厂 14function createSecureServiceProxy(userRole) { 15 let instance = null; 16 17 const handler = { 18 // 属性访问拦截器 19 get(target, prop, receiver) { 20 // 懒加载初始化:仅在首次使用时创建服务 21 if (!instance) { 22 instance = new DataService(); 23 } 24 25 // 拦截方法调用 26 if (prop === 'fetch') { 27 return (key) => { 28 // 访问控制:非管理员用户禁止访问 secret 数据 29 if (key === 'secret' && userRole !== 'admin') { 30 throw new Error('Access denied'); 31 } 32 // 将调用转发到真实的 DataService 33 return instance.fetch(key); 34 }; 35 } 36 37 // 默认:转发到真实目标 38 return Reflect.get(target, prop, receiver); 39 }, 40 }; 41 42 // 返回强制懒加载 + 访问控制的代理 43 return new Proxy({}, handler); 44} 45 46// 使用示例 47const adminProxy = createSecureServiceProxy('admin'); 48console.log('Admin sees:', adminProxy.fetch('secret')); 49 50const guestProxy = createSecureServiceProxy('guest'); 51console.log('Guest sees:', guestProxy.fetch('public')); 52 53try { 54 console.log('Guest tries secret:'); 55 const result = guestProxy.fetch('secret'); 56 console.log(result); 57} catch (e) { 58 console.error(e.message); 59}

TypeScript

1// 重型服务模拟 2class DataService { 3 private data = { secret: 'classified', public: 'hello' }; 4 constructor() { 5 console.log('Initializing heavy DataService...'); 6 } 7 8 fetch(key: keyof typeof this.data) { 9 return this.data[key]; 10 } 11} 12 13// 代理工厂 14function createSecureServiceProxy(userRole: 'admin' | 'guest') { 15 let instance: DataService | null = null; 16 17 const handler: ProxyHandler<DataService> = { 18 // 属性访问拦截器 19 get(target, prop, receiver) { 20 // 懒加载初始化:仅在首次使用时创建服务 21 if (!instance) { 22 instance = new DataService(); 23 } 24 25 // 拦截方法调用 26 if (prop === 'fetch') { 27 return (key: keyof typeof target['data']) => { 28 // 访问控制:非管理员用户禁止访问 secret 数据 29 if (key === 'secret' && userRole !== 'admin') { 30 throw new Error('Access denied'); 31 } 32 // 将调用转发到真实的 DataService 33 return instance!.fetch(key); 34 }; 35 } 36 37 // 默认:转发到真实目标 38 return Reflect.get(target, prop, receiver); 39 }, 40 }; 41 42 // 返回强制懒加载 + 访问控制的代理 43 return new Proxy({} as DataService, handler); 44} 45 46// 使用示例 47const adminProxy = createSecureServiceProxy('admin'); 48console.log('Admin sees:', adminProxy.fetch('secret')); 49 50const guestProxy = createSecureServiceProxy('guest'); 51console.log('Guest sees:', guestProxy.fetch('public')); 52 53try { 54 console.log('Guest tries secret:'); 55 const result = guestProxy.fetch('secret'); 56 console.log(result); 57} catch (e) { 58 console.error(e.message); 59}

适配器模式:在依赖项之间标准化接口

在配置对象上记录每一次属性读取