阅读 80

一个Javascript 代理 Proxy 的成长之旅

“这是我参与更文挑战的第5天,活动详情查看: 更文挑战

Proxy 按字面意思就是代理,其 API官方使用手册见 MDN

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

我们将 Proxy 理解为现实生活中的代理商,通过几个常见的卖货场景来学习一下 Proxy。

一个新手代理商

一个新手代理商,一脸懵逼,只管代理了,但啥都不干啥。

const target = {
    who: "我是谁?",
    where: "我在哪里?"
};

const handler1 = {};

const proxy1 = new Proxy(target, handler1);

console.log(proxy1.who); // => 我是谁?
console.log(proxy1.where); // => 我在哪里?

复制代码

一个开始知道赚钱的代理商

懵逼之后,开始上道,代理的本质是要赚钱,所以我们统一将售价对外展示为成本价的 1.5 倍吧。

const originPrice = {
    water: 10,
    rice: 20
};

const handler2 = {
    get(target, key) {
        return target[key] * 1.5;
    }
};

const soldPrice = new Proxy(originPrice, handler2);

console.log(soldPrice.water); // => 15
console.log(soldPrice.rice); // => 30
复制代码

一个开始懂得处理库存的代理商

做生意很关键的一点的要管理好库存信息,知道库存才知道什么时候好进货,以及进多少。

const quantity = {
    water: 5,
    rice: 3
};

const handler3 = {
    set(target, key, value) {
        target[key] = value;
        console.log(`更新${key}的库存为${value}`);
        return true;
    }
};

const quantitySet = new Proxy(quantity, handler3);

quantitySet.water = 15; // => 更新water的库存为15
quantitySet.rice = 13; // => 更新rice的库存为13

console.log(quantitySet.water); // => 15
console.log(quantitySet.rice); // => 13
复制代码

某一天,太忙懵逼了,一不小心库存输入太大了,导致货不对量了。所以我们还可以加入一个输入限制。

const quantity = {
    rice: 3
};

const handler3 = {
    set(target, key, value) {
        if (value > 100) {
            console.log(`${key}的库存怕不是搞错了吧。再复核一下?`return false;
        }
        target[key] = value;
        console.log(`更新${key}的库存为${value}`);
        return true;
    }
};
...

quantitySet.rice = 101; // => rice的库存怕不是搞错了吧。再复核一下?
console.log(quantitySet.rice); // => 3

复制代码

一个开始懂得捂货的代理商

好东西坚决不卖~捂着先。开始奸商之道。

const goods = {
    '矿泉水': 100,
    '茅台': 10,
    _privateDVD: 10,
};

const handler4 = {
    has(target, key) {
        if (key === '茅台' || key.startsWith('_')) {
            console.log('打死我都不会承认自己有的');
            return false;
        }
        console.log('有有有,大量的有');
        return Reflect.get(target, key);
    }
};

const sellGoods = new Proxy(goods, handler4);

console.log('茅台' in sellGoods); // false
console.log('_privateDVD' in sellGoods); // false
console.log('矿泉水' in sellGoods); // true
复制代码

一个亏本清仓甩卖的代理商

不说了,流过的眼泪就是自己的智商税。

const goodsInfo = {
    'saltWater': 100,
    '茅台': 1,
    '_privateDVD': 1
};

const readonlyKeys = ['茅台', '_privateDVD'];

const sellGoods2 = new Proxy(goodsInfo, {
    deleteProperty(target, key) {
        if (readonlyKeys.includes(key)) {     
            throw new Error(`${key}这种货怎么可能清仓`);
            return;
        }

        console.log(`delete: ${key}`);
        delete target[key];
        return true;
    }
});
console.log(sellGoods2.saltWater, goodsInfo.saltWater); // => 100 100
delete sellGoods2.saltWater; // => delete: saltWater
console.log(sellGoods2.saltWater, goodsInfo.saltWater); // => undefined undefined
// delete sellGoods2['茅台']; // => throw error
delete sellGoods2['_privateDVD']; // => throw error
        
复制代码

Proxy的小结

通过上面的几个案例,我想我们对 Proxy 代理之路已经有了初步的概念。文中出现的几个 handler

  • get handler
  • set handler
  • has handler
  • deleteProperty handler

是 Proxy 最常见的几种 handler,我们可以在代理上原始的 target 之后,再封装自己的业务逻辑。

其强大的特性也被 vue3 所直接使用,性能进而得到了大幅提升。

但其最大的兼容性问题是不被 IE 支持,这也是为什么 vue3 放弃 IE 的原因了。

你会在项目中使用 Proxy 吗。

文章分类
前端
文章标签