代理模式

情景: 小明追女生 A

  • 非代理模式: 小明 =花=> 女生 A
  • 代理模式: 小明 =花=> 让女生 A 的好友 B 帮忙 =花=> 女生 A

代理模式的特点

  • 代理对象和本体对象具有一致的接口, 对使用者友好

代理模式的种类有很多, 在 JS 中最常用的为虚拟代理和缓存代理。

虚拟代理实现图片预加载

下面这段代码运用代理模式来实现图片预加载, 可以看到通过代理模式巧妙地将创建图片与预加载逻辑分离, 并且在未来如果不需要预加载, 只要改成请求本体代替请求代理对象就行。

const myImage = (function() {
  const imgNode = document.createElement('img')
  document.body.appendChild(imgNode)
  return {
    setSrc: function(src) {
      imgNode.src = src
    }
  }
})()

const proxyImage = (function() {
  const img = new Image()
  img.onload = function() { // http 图片加载完毕后才会执行
    myImage.setSrc(this.src)
  }
  return {
    setSrc: function(src) {
      myImage.setSrc('loading.jpg') // 本地 loading 图片
      img.src = src
    }
  }
})()

proxyImage.setSrc('http://loaded.jpg')

缓存代理实现乘积计算

const mult = function() {
  let a = 1
  for (let i = 0, l; l = arguments[i++];) {
    a = a * l
  }
  return a
}

const proxyMult = (function() {
  const cache = {}
  return function() {
    const tag = Array.prototype.join.call(arguments, ',')
    if (cache[tag]) {
      return cache[tag]
    }
    cache[tag] = mult.apply(this, arguments)
    return cache[tag]
  }
})()

proxyMult(1, 2, 3, 4) // 24

小 tip

在开发时候不要先去猜测是否需要使用代理模式, 如果发现直接使用某个对象不方便时, 再来优化不迟。