设计模式-代理模式

262 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

代理模式是指:由于一个对象不能直接引用另外一个对象,因此需要通过增加一个代理对象,在两个对象起到中介作用,其核心就是以目标对象为原型创造一个代理对象,通过代理对象实现对目标对象的访问,而不是直接访问目标对象

为什么不直接访问目标对象呢?

在代理对象访问目标对象这个过程中可以增加一些额外的逻辑处理、操作等事情,在不改变目标对象的前提下扩展了其能力,大大的增加了可操控空间

在日常生活中,代理模式非常常见,比如许多艺人的经纪人,各种中介人员等

事件委托代理

什么是事件冒泡?捕获?

当一个事件触发,会分为三个阶段:捕获阶段、目标阶段和冒泡阶段

捕获阶段:是指从当一个事件发生之后,事件从文档的根节点流向目标对象节点。途中经过各个层次的DOM节点,并在各节点上触发捕获事件,直到到达事件的目标节点,其是自上而下的去触发事件

目标阶段:事件经过捕获阶段不断向下传递,一直到达目标节点,事件就进入了目标阶段。事件在目标节点上被触发

冒泡阶段:事件在目标阶段触发之后会逆向回流,它会随着DOM树一层层向上冒泡,回溯到根节点,其是自下而上的去触发事件

接下来看看如何利用代理模式完成事件委托代理

首先创建dom结构:

<ul id="ul">
  <li>11</li>
  <li>22</li>
  <li>33</li>
</ul>

此时期望在点击每个li的时候,可以获取到对应的内容,若是给每一个li绑定事件,那么有多少个元素即需要绑定多少次,若是有10000个,就需要绑定10000次,对于性能是非常影响的,因此通过代理模式将事件代理在ul上,根据事件触发的阶段可知,当点击某个li时,事件会在目标 阶段触发之后向上冒泡,而且此时可以通过event得知这个事件从哪里来,内容是什么,只需要绑定一次即可,可以很好的提高性能

window.onload = () => {
    ul.addEventListener("click", (e) => {
        console.log(e.target.innerHTML); // 点击li时 打印对应的内容
    });
};

Proxy

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写

Proxy是JS自带的代理模式的实现

const obj = {
    name: "nordon",
    age: 12,
    getName() {
        console.log(`调用了getName函数: ${this.name}`);
    },
};

const proxyObj = new Proxy(obj, {
    get: function (target, propKey, receiver) {
        console.log(`获取: ${propKey}!`);
        return Reflect.get(target, propKey, receiver);
    },
    set: function (target, propKey, value, receiver) {
        console.log(`设置: ${propKey}!`);
        if(propKey === 'age' && value < 0) {
            throw new Error('年龄设置不合理')
        }
        return Reflect.set(target, propKey, value, receiver);
    },
});

proxyObj.getName();
proxyObj.name = 'wy';

当我们通过proxyObj进行属性和函数的访问和修改,都会触发代理,我们可以在代理中去增加额外的逻辑

若是proxyObj.age = -12设置属性age时,控制台会报错:Uncaught Error: 年龄设置不合理,因为在set中对于年龄的设置做了逻辑判断