目录
一、代理模式的定义和概念
二、代理模式的实现方式
1.ES6 Proxy 实现动态代理:
2.手动实现静态代理:
三、代理模式的应用场景
1.图片懒加载:
2.数据缓存:
3.权限控制:
四、代理模式的优点:
1.解耦目标对象和代理对象:
2.增强目标对象的功能:
3.提高性能:
五、代理模式的缺点
1.增加系统复杂性:
2.可能会降低性能:
六、代理模式的注意事项
1.代理对象和目标对象的接口一致性:
2.避免过度使用代理:
3.处理好代理对象和目标对象的生命周期:
一、代理模式的定义和概念
代理模式是一种设计模式,它为其他对象提供一种代理以控制对这个对象的访问。在前端中,代理模式可以用于拦截对目标对象的访问,并在访问前后执行一些额外的操作,比如缓存数据、验证权限、记录日志等。
二、代理模式的实现方式
1.ES6 Proxy 实现动态代理:
ES6 引入了Proxy
对象,可以方便地创建一个代理对象。Proxy
接收两个参数,第一个是目标对象,第二个是一个处理程序对象,其中可以定义各种捕获器方法来拦截对目标对象的操作。
示例:
const targetObject = {name: 'original object',value: 42,};const proxyObject = new Proxy(targetObject, {get(target, property) {console.log(`Getting property ${property}`);return target[property];},set(target, property, value) {console.log(`Setting property ${property} to ${value}`);target[property] = value;return true;},});console.log(proxyObject.name); // 输出:Getting property name,然后是'original object'proxyObject.value = 100; // 输出:Setting property value to 100
2.手动实现静态代理:
创建一个代理对象,该对象具有与目标对象相同的接口,并在代理对象的方法中调用目标对象的方法,并可以添加额外的逻辑。
示例:
// 目标对象class Target {doSomething() {console.log('Target is doing something.');}}// 代理对象class Proxy {constructor(target) {this.target = target;}doSomething() {console.log('Before calling target.');this.target.doSomething();console.log('After calling target.');}}const target = new Target();const proxy = new Proxy(target);proxy.doSomething();
三、代理模式的应用场景
1.图片懒加载:
当页面中有很多图片时,可以使用代理模式来实现图片的懒加载。当图片进入可视区域时,再真正加载图片。
示例:
class Image {constructor(src) {this.src = src;}load() {const img = new Image(this.src);img.onload = () => {console.log(`Image ${this.src} loaded.`);};img.src = this.src;}}class ImageProxy {constructor(src) {this.src = src;this.image = null;}load() {if (!this.image) {this.image = new Image(this.src);}if (this.isInViewport()) {this.image.load();}}isInViewport() {// 判断图片是否在可视区域的逻辑return true; // 这里简化为始终返回 true}}const proxyImage = new ImageProxy('image.jpg');proxyImage.load();
2.数据缓存:
当从服务器获取数据时,可以使用代理模式来缓存数据。如果数据已经被缓存,直接从缓存中获取数据,而不需要再次从服务器获取。
示例:
class DataFetcher {fetchData() {console.log('Fetching data from server...');return 'data from server';}}class DataFetcherProxy {constructor() {this.dataFetcher = new DataFetcher();this.cache = null;}fetchData() {if (!this.cache) {this.cache = this.dataFetcher.fetchData();}return this.cache;}}const proxy = new DataFetcherProxy();console.log(proxy.fetchData()); // 输出:Fetching data from server...,然后是'data from server'console.log(proxy.fetchData()); // 直接从缓存中获取数据,不再从服务器获取
3.权限控制:
在前端应用中,可以使用代理模式来控制用户对某些功能的访问权限。如果用户没有权限访问某个功能,代理对象可以阻止对目标对象的调用。
示例:
class TargetFunction {performAction() {console.log('Performing sensitive action.');}}class PermissionProxy {constructor(target, hasPermission) {this.target = target;this.hasPermission = hasPermission;}performAction() {if (this.hasPermission) {this.target.performAction();} else {console.log('You do not have permission to perform this action.');}}}const target = new TargetFunction();const proxyWithPermission = new PermissionProxy(target, true);proxyWithPermission.performAction(); // 输出:Performing sensitive action.const proxyWithoutPermission = new PermissionProxy(target, false);proxyWithoutPermission.performAction(); // 输出:You do not have permission to perform this action.
四、代理模式的优点:
1.解耦目标对象和代理对象:
代理对象和目标对象实现了相同的接口,客户端只需要与代理对象交互,而不需要知道目标对象的具体实现。这样可以降低客户端与目标对象之间的耦合度,提高代码的可维护性和可扩展性。
2.增强目标对象的功能:
代理对象可以在不修改目标对象的情况下,为目标对象添加额外的功能,比如缓存、日志记录、权限控制等。这样可以提高代码的复用性和灵活性。
3.提高性能:
代理对象可以在需要的时候才加载目标对象,或者缓存目标对象的结果,从而提高系统的性能。
五、代理模式的缺点
1.增加系统复杂性:
引入代理对象会增加系统的复杂性,特别是在使用动态代理时,需要理解Proxy
对象的各种捕获器方法的使用。
2.可能会降低性能:
如果代理对象的实现不当,可能会降低系统的性能。比如,在每次访问目标对象时都进行权限检查,可能会导致性能下降。
六、代理模式的注意事项
1.代理对象和目标对象的接口一致性:
代理对象和目标对象应该实现相同的接口,这样客户端才能无缝的使用代理对象替换目标对象。
2.避免过度使用代理:
代理对象虽然可以为目标对象添加很多功能,但过度使用代理可能会导致系统过于复杂,难以维护。应该根据实际需求合理使用代理模式。
3.处理好代理对象和目标对象的生命周期:
在某些情况下,代理对象可能需要在目标对象被销毁时也进行相应的清理操作。应该确保代理对象和目标对象的生命周期管理正确。