Skip to content

介绍

  • 使用者无权访问目标对象
  • 中间加代理,通过代理做授权和控制

示例

  • 科学上网,访问 GitHub.com
  • 明星经纪人

常见使用场景

  • 网页事件代理
html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="div1">
      <a href="#">a1</a>
      <a href="#">a2</a>
      <a href="#">a3</a>
      <a href="#">a4</a>
      <a href="#">a5</a>
      <a href="#">a6</a>
    </div>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script>
      let div1 = document.getElementById('div1')
      //监听a标签上的点击事件,不可能对a一个一个的去绑定
      div1.addEventListener('click', function (e) {
        let target = e.target
        if (target.nodeName === 'A') {
          console.log(target.innerHTML)
        }
      })
    </script>
  </body>
</html>
  • jQuery的$.proxy
html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="div1">
      <a href="#">a1</a>
      <a href="#">a2</a>
      <a href="#">a3</a>
      <a href="#">a4</a>
      <a href="#">a5</a>
      <a href="#">a6</a>
    </div>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script>
      // $("#div1").click(function () {
      // 	$(this).addClass("red");
      // });
      // $("#div1").click(function () {
      // 	setTimeout(function () {
      //     // this 不符合期望
      // 		$(this).addClass("red");
      // 	}, 1000);
      // });

      // $("#div1").click(function () {
      //   var _this = this;
      // 	setTimeout(function () {
      //     // _this 符合期望
      // 		$(_this).addClass("red");
      // 	}, 1000);
      // });

      // $("#div1").click(() => {
      // 	setTimeout(() => {
      // 		$(this).addClass("red");
      // 	}, 1000);
      // });

      $('#div1').click(function () {
        setTimeout(
          $.proxy(function () {
            $(this).addClass('red')
          }, this),
          1000
        )
      })
    </script>
  </body>
</html>
  • es 6的proxy
javascript
//明星
let star = {
  name: 'dd',
  age: 25,
  phone: '明星电话:189****05**',
}

//经纪人
let agent = new Proxy(star, {
  //target是要代理的对象,key是要获取的属性值
  get: function (target, key) {
    if (key === 'phone') {
      //返回经纪人的电话,不会把明星的电话直接给你
      return '经纪人电话:189******3*'
    }
    if (key === 'price') {
      //明星不报价,经纪人谈价格
      return '12K'
    }
    return target[key]
  },
  set: function (target, key, value) {
    if (key === 'customPrice') {
      if (value < 100000) {
        //最低10万
        throw new Error('价格太低')
      } else {
        target[key] = value
        return true
      }
    }
  },
})

console.log(agent.name)
console.log(agent.phone)
console.log(agent.price)

agent.customPrice = 150000
console.log('agent.customPrice:' + agent.customPrice)

代理模式代码示例

javascript
class ReadImg {
  constructor(fileName) {
    this.fileName = fileName
    this.loadFromDisk()
  }
  dispaly() {
    console.log('display... ' + this.fileName)
  }
  loadFromDisk() {
    console.log('loading... ' + this.fileName)
  }
}

class ProxyImg {
  constructor(fileName) {
    this.realImg = new ReadImg(fileName)
  }
  dispaly() {
    this.realImg.dispaly()
  }
}

// test
let proxyImg = new ProxyImg('pic.png')
proxyImg.dispaly()

设计原理验证

  • 代理类和目标类分离,隔离开目标类和使用者
  • 符合开放封闭原则

区分

代理模式 VS 适配器模式

  • 适配器模式:提供一个不同的接口(如不同版本的插头)
  • 代理模式:提供一模一样的接口

代理模式 VS 装饰器模式

  • 装饰器模式:扩展功能,原有功能不变且可直接使用
  • 代理模式: 显示原有功能,但是经过限制或者阉割之后的