今天我们来学习JavaScript常用的设计模式——代理模式

代理在现实生活中一般就是指代表授权方处理事务。在法律上,是指代理人,被授权方准许以其人名义,与第三者为法律行为的意思表示。因获得授权而为之的法律行为,可以对授权方直接发生法律上效力。

也就是说:当客户不方便直接访问某个对象的时候,可以提供一个代理对象供客户访问。代理对象对请求做出一系列处理之后,再将请求转交给本体对象。

# 定义

为⼀个对象提供⼀个代⽤品或占位符,以便控制对它的访问。替身对象可对请求预先进⾏处理, 再决定是否转交给本体对象。

代理模式也有很多种,比如保护代理和虚拟代理。保护代理用于控制不同权限对象目标对象的访问;虚拟代理是指把一些开销很大的对象,延迟到真正需要的时候才去创建。

# 应用场景

当我们不⽅便直接访问某个对象时,或不满⾜需求时,可考虑使⽤⼀个替身对象来控制该对象的访问。

下面我们以一个图片预加载的例子来看看虚拟代理模式:

# 使用前

先用一张加载中的图片占位,然后异步加载图片,等图片加载完成填充至img节点中

原生函数

const rawImage = (() => {
  // 创建图片节点
  const imgNode = document.createElement("img");
  // 将图片节点添加到页面
  document.body.appendChild(imgNode);
  // 返回一个对象,提供一个接口
  return {
    // 对象中有一个方法,接受图片url
    setSrc: (src) => {
      // 将图片节点的src指向本地文件
      imgNode.src = "./loading.gif";
      // 创建一个新的图片
      const img = new Image();
      // 将图片的src指向传入的src
      img.src = src;
      // 当图片加载完毕,将图片节点的src改成img的src
      img.onload = () => {
        imgNode.src = this.src;
      };
    },
  };
})();
rawImage.setSrc("http://xxx.gif");

违反了我们设计原则中的单一职责原则,什么操作都在原生函数中完成,所以我们需要解耦

# 使用后

原生函数仅提供 创建图片节点、设置图片链接 的功能

const rawImage = (() => {
  const imgNode = document.createElement("img");
  document.body.appendChild(imgNode);
  return {
    setSrc: (src) => {
      imgNode.src = src;
    },
  };
})();

设置一个代理函数,通过代理来做一些操作,加载图片、设置加载图

const proxyImage = (() => {
  // 创建新的图片
  const img = new Image();
  // 当图片加载完成,调用原生函数的修改src接口
  img.onload = () => {
    rawImage.setSrc(this.src);
  };
  
  return {
    // 设置加载图片
    setSrc: (src) => {
      rawImage.setSrc("./loading.gif");
      img.src = src;
    },
  };
})();
proxyImage.setSrc("http://xxx.gif");

这样写的好处是:使用代理函数来控制用户对原生函数的访问,并且可以在代理函数中进行一些额外的操作。

上次更新: 2022/4/18 18:10:13