学习JavaScript 设计模式 - 代理模式

667 阅读1分钟

本章讲一个结构型设计模式-代理模式( Proxy Pattern )

定义

为一个对象提供一种代理以便控制对它的访问, 就是增加了一种访问方式, 比如某一个花销很大的动作, 可以通过按需加载的方式, 等用到它再去创建

代理模式也分很多种, 下面图也只是列了一部分, 我挑几个前端常用的、并且我了解的写一写

graph TD
代理模式 --> 远程代理
代理模式 --> 虚拟代理
代理模式 --> 缓存代理
代理模式 --> 保护代理
代理模式 --> 智能引用代理

虚拟代理

前端比较常用的虚拟代理比如图片懒加载、预加载 (有些人把这两混淆了), 这里举个预加载例子吧, 比如支付宝饿了吗外卖 经常有那个刮卡或者翻牌红包, 这种情况就可以用预加载

抽奖.gif

    //创建三张卡牌
    <div class="card-box" @click="handleClick">
        <img :src="src" data-src="~D:/文章图片/hbmz.png" >
        <img :src="src" data-src="~D:/文章图片/hbmz.png" >
        <img :src="src" data-src="~D:/文章图片/hbmz.png" >
    </div>
    
    //这里直接预加载几张抽奖结果图片, 但是不让它显示, 待会用这里的图片替换用户点击的那张卡牌
    //实际情况这里不止一张, 需要预加载所有翻牌结果图, 这里只是拿一张举例
    <img id="img" src="~D:/文章图片/hbmz.png" style="display: none">

暗度陈仓

    class IM {
        constructor(img) {
            this.img = img
        }
        replace(src) {
            this.img.src = src
        }
    }
    
    function handleClick(e) {
        const preload = document.getElementById('img')  
        new IM( e.target ).replace( preload.src )
    }

缓存代理

前端经典的缓存代理 - 阶乘

  function factorial(n) {
      console.log('重新计算阶乘')
      if (n < 2) {
          return n
      } else {
          return n * factorial(n-1)
      }  
  }
    
   
  factorial(3)
  factorial(3) 
  //这样执行两次就会打印 2 * 3 次 

有时候我们不想每次重新计算阶乘, 这时候我们添加下缓存

  function factorial(n) {
      console.log('重新计算阶乘')
      if (n < 2) {
          return n
      } else {
          return n * factorial(n-1)
      }  
  }
  
  function proxy(fn) {
        const catchObject = {}
        
        return function(key) {
            if (key in catchObject) {
                return catchObject[key]
            } else {
                return catchObject[key] = fn(key)
            }                
        }
  }
    
    
    const instance = proxy(factorial)
    instance(3)
    instance(3)
    instance(3)
    
    //这时候我们发现无论 “重复” 执行多少次, 都只计算了一次

前端经典的缓存代理 - tab

    <div class="tab" onClick="handleClick">
        <span> 1 </span>
        <span> 2 </span>
        <span> 3 </span>
    </div>
    <div class="content">
        <!-- 根据tab获取不同数据显示在这 -->
    </div>
    
    class ProxyTab {
        static catch = {}
        constructor(target) {
            if (!ProxyTab.catch[target]) {
                ProxyTab.catch[target] = this.http()
            }
        }
        http() {
           return axios.get('xxx') 
        }
    }
    
    function handleClick(e) {
        new ProxyTab(e.target)
    }

类似场景还有分页、事件代理(ul代理li事件), 这次就先写这么多了

最后的轻语

开始并完成一件事情, 比做好它更重要。
因为只要开始了, 你就有机会把它做得更好
“现在” 就是最好的时机
不管怎样, 只要开始就好