1. 由于一个对象不能直接引用另外一个对象,所以需要通过代理对象在这两个对象之间起到中介作用

  2. 适用 场景

    • 保护目标对象:客户端 只与 代理类 进行交互,不清楚 目标对象 的具体细节; 相当于 租客 只与 中介 进行交互,不知道房东的信息;
    • 增强目标对象:代理类 在 目标对象的基础上,对 目标对象的功能 进行增强;
  3. 优点

    • 分离目标对象:代理模式 能将 代理对象 与 真实被调用的 目标对象 分离;
    • 降低耦合:在一定程度上,降低了系统耦合性,扩展性好;
    • 保护目标对象:代理类 代理目标对象的业务逻辑,客户端 直接与 代理类 进行交互,客户端 与 实际的目标对象之间没有关联;
    • 增强目标对象:代理类 可以在 目标对象基础上,添加新的功能;
  4. 缺点

    • 类个数增加:代理模式 会造成系统中 类的个数 增加,比不使用代理模式增加了代理类,系统的复杂度增加;(所有的设计模式都有这个缺点)
    • 性能降低:在 客户端目标对象 之间,增加了一个代理对象,造成 请求处理速度变慢

类图

实现代码

class Goole {
    constructor() { }
    get() {
        return 'google';
    }
}

class Proxy {
    constructor() {
        this.google = new Goole();
    }
    get() {
        return this.google.get();
    }
}

let proxy = new Proxy();
let ret = proxy.get();
console.log(ret);

经典场景

事件委托

  • 事件捕获指的是从 document 到触发事件的那个节点,即自上而下的去触发事件;

  • 事件冒泡是自下而上的去触发事件

  • 绑定事件方法的第三个参数,就是控制事件触发顺序是否为事件捕获,true 为事件捕获;false 为事件冒泡,默认 false;

<body>
    <ul id="list">
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </ul>
    <script>
        let list = document.querySelector('#list');
        list.addEventListener('click', event => {
            alert(event.target.innerHTML);
        });
    </script>
</body>

图片懒加载

  1. 服务端

    let express = require('express');
    let path = require('path')
    let app = express();
    
    app.get('/images/loading.gif', function (req, res) {
        res.sendFile(path.join(__dirname, req.path));
    });
    
    app.get('/images/:name', function (req, res) {
        setTimeout(() => {
            res.sendFile(path.join(__dirname, req.path));
        }, 2000);
    });
    
    app.get('/', function (req, res) {
        res.sendFile(path.resolve('index.html'));
    });
    
    app.listen(8080);
    
  2. 客户端

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>
        <style>
        * {
            padding: 0;
            margin: 0;
        }
    
        ul,
        li {
            list-style: none;
        }
    
        #background {
            position: absolute;
            border: 1px solid green;
            right: 10px;
            top: 10px;
        }
    
        #background li {
            float: left;
            margin-left: 10px;
            text-align: center;
            border: 1px solid red;
            border-radius: 5px;
        }
    
        #myImage {
            width: 600px;
            height: 400px;
            margin: 100px auto;
        }
    
        #myImage img {
            width: 100%;
            height: 100%;
        }
        </style>
    </head>
    
    <body>
        <ul id="background">
            <li data-src="/images/bg1.jpg">图片1</li>
            <li data-src="/images/bg2.jpg">图片2</li>
        </ul>
        <div id="myImage"></div>
    
    </body>
    
    <script>
        let container = document.querySelector("#background");
        let myImage = document.querySelector("#myImage");
    
        let Background = (function () {
            let img = new Image();
            myImage.appendChild(img);
            return {
                set(src) {
                    img.src = src;
                },
            };
        })();
    
        // 代理
        let LoadingBackground = (function () {
            let img = new Image();
            img.onload = function () {
                Background.set(this.src);
            };
            return {
                set(src) {
                    Background.set(`/images/loading.gif`);
                    img.src = src;
                },
            };
        })();
    
        container.addEventListener("click", function (event) {
            let src = event.target.dataset.src;
            LoadingBackground.set(src + "?ts=" + Date.now());
        });
    </script>
    </html>
    

防抖代理

跨域代理

$.proxy

  • 接受一个函数,然后返回一个新函数,并且这个新函数始终保持了特定的上下文语境(类似 bind);

  • jQuery.proxy(function, context) function 为执行的函数,content 为函数的上下文,this 值会被设置成这个 object 对象;

<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
    let btn = document.getElementById('btn');
    btn.addEventListener('click', function () {
        setTimeout($.proxy((function () {
            $(this).css('color', 'red');
        }), this), 1000);
        // 等价
        // function setColor() {
        //     $(this).css('color', 'red');
        // }
        // setColor = setColor.bind(this);
        // setTimeout(setColor, 1000);
    });
</script>

Proxy

  • Proxy 用于修改某些操作的默认行为;

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

let wang = {
  name: 'wangy',
  age: 29,
  height: 165
}

let wangMama = new Proxy(wang, {
  get(target, key) {
    if (key == 'age') {
      return wang.age - 1;
    } else if (key == 'height') {
      return wang.height + 5;
    }
    return target[key];
  },
  set(target, key, val) {
    if (key == 'boyfriend') {
      let boyfriend = val;
      if (boyfriend.age > 40) {
        throw new Error('太老');
      } else if (boyfriend.salary < 20000) {
        throw new Error('太穷');
      } else {
        target[key] = val;
        return true;
      }
    }
  }
});

console.log(wangMama.age);
console.log(wangMama.height);
wangMama.boyfriend = {
  age: 41,
  salary: 3000
}
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 类图
  2. 2. 实现代码
  3. 3. 经典场景
    1. 3.1. 事件委托
    2. 3.2. 图片懒加载
    3. 3.3. 防抖代理
    4. 3.4. 跨域代理
    5. 3.5. $.proxy
    6. 3.6. Proxy