js中的代理模式

代理模式

代理模式的定义:为一个对象提供一个代用品或占位符,以便控制对它的访问

代理模式被运用到vue的响应式数据上,在ES6之前用Object.defineProperty,在ES6后使用Proxy来实现代理。

虚拟代理

虚拟代理用来收集某个时间内对代理对象的访问,在某个时间时把收集到的访问全部执行,某种意义上可以看作是带有收集功能的防抖。

以点击事件为例:

<span>2</span>
<button>+1</button>

<script>
function add(addNum) {
    span.innerText += addNum;
}
btn.addEventListener("click", function (event) {
    add(3);
});
</script>

这是个很简单的操作,点击一下按钮,页面上的数字会逐渐笑得更开心。

假设点击事件是个会向服务器发送请求的操作,如果用户疯狂点击,会给服务器带来巨大压力,这时候可以这样设计:无论用户点击了多少次,只有在点击另一个确定按钮后才会发送请求,这样就既能确保操作的有效性还能提升性能。

function add(addNum) {
    span.innerText += addNum;
}
const proxyAdd = (function () {
    let number = "";
    return {
        input(addNum) {
            number += addNum;
        },
        add() {
            add(number);
        },
    };
})();
btn.addEventListener("click", function (event) {
    proxyAdd.input(3);
});
emit.addEventListener("click", function (event) {
    proxyAdd.add();
});

这样就通过proxyAdd实现了对add方法的虚拟代理。

缓存代理

在JS中实现缓存代理和单例模式都是一个思路:使用闭包制造一个缓存,如果有缓存则直接把它返回,在单例模式里只有一个缓存,而用缓存代理则需要使用一个对象记录使用过哪些参数实例化过对象。

好在Proxy里提供了construct捕获其,用来捕捉对函数的new操作符,具体可以看MDN

这个例子是在实例化对象时将指定计算次数的斐波那契数放入一个属性上,通过对比能明显看到运行的差距:

//! 计算斐波那契数
const getFib = (number) => {
    if (number <= 2) {
        return 1;
    } else {
        return getFib(number - 1) + getFib(number - 2);
    }
};
//! 目标类
class getNum {
    constructor(number) {
        this.number = getFib(number);
    }
}
//! 代理类
const ProxyGetNum = (function () {
    const cache = Object.create(null);
    return new Proxy(getNum, {
        construct(target, args) {
            const argStr = args.join(" "); //? 获得实例化时的所有参数
            return cache[argStr] ?? (cache[argStr] = new target(...args));
        },
    });
})();

console.time("getNum");
console.log(new getNum(40));
console.log(new getNum(40));
console.timeEnd("getNum");

console.time("proxy");
console.log(new ProxyGetNum(40));
console.log(new ProxyGetNum(40));
console.timeEnd("proxy");

热门相关:无量真仙   夫人,你马甲又掉了!   夫人你马甲又掉了   战神   名门天后:重生国民千金