关于javascript:JavaScript代理的惊人威力

明天咱们要学习的是ECMAScript 6的代理。咱们将在本文中波及以下主题。

  • 什么是代理
  • 代理人在口头
  • 谁应用代理
  • 应用案例和实例
  • 资源

让咱们开始吧:)

什么是代理

如MDN网站所述。

Proxy对象使你可能为另一个对象创立一个代理,它能够拦挡和从新定义该对象的基本操作。

他们在解释什么是代理的时候,说它能够创立一个代理**,这有点搞笑。当然,他们并没有错,但咱们能够简化这个说法,使其更加敌对,说

_Proxy_对象能够让你包裹指标对象,通过这样做,咱们能够拦挡和从新定义该对象的基本操作。

基本上,它的意思是咱们要把一个对象,用Proxy包裹起来,这将容许咱们创立一个 “暗藏 “的门,并管制所有对所需对象的拜访。

一个小插曲,Proxy也是一种软件设计模式,你肯定要浏览一下(维基百科链接)。

const target = {
  message1: "hello",
  message2: "everyone"
};

const handler = {};

const proxy = new Proxy(target, handler);

一个 “代理 “是用两个参数创立的。

  • “target”:你要包裹的原始对象(代理)。
  • handler:定义哪些操作将被拦挡,以及如何从新定义被拦挡的操作的对象,也能够调用 “陷阱”。

大多数浏览器都反对代理,但也有一些老的浏览器不反对(当然是IE),你能够查看残缺的列表这里。google有一个polyfill的Proxies,但它不反对所有的Proxy性能。

当初咱们晓得了什么是代理,咱们想看看咱们能用它做什么。

代理人在口头

让咱们设想一下,咱们是A Bank。咱们想晓得每次银行账户余额被拜访并被告诉上。咱们将应用最简略的handler操作/陷阱。get

在下面的例子中,咱们有一个银行账户对象,外面有我的名字和2020的余额。

const bankAccount = {
  balance: 2020,
  name: 'Georgy Glezer'
};

const handler = {
   get: function(target, prop, receiver) {
    if (prop === 'balance') {
    console.log(`Current Balance Of: ${target.name} Is: ${target.balance} `);
    }

    return target[prop];
  }
};

const wrappedBankAcount = new Proxy(bankAccount, handler);

wrappedBankAcount.balance; // access to the balance

// OUTPUT:
// Current Balance Of: Georgy Glezer Is: 2020
// 2020

这次的解决者对象实现的是get操作/陷阱,它接管一个有3个参数的函数和get的返回值。

  • target。被拜访的对象(咱们封装的对象)。
  • prop: 被拜访的属性。在咱们的例子中被拜访的属性–这里是 “balance”。
  • receiver:接受者。能够是代理,也能够是继承自代理的对象。

咱们定义了一个条件,如果被拜访的属性是”_balance”_,咱们将告诉(log)余额和以后用户名,并返回属性_”balance”_。

从输入中能够看到,一旦 “余额 “属性被拜访,咱们通过应用代理和设置get操作/陷阱,很容易就告诉(log)了这次拜访。

咱们持续用咱们Bank的想法,要求每次有人从银行账户中取钱,咱们都要告诉一下。而另一个约束条件是,银行不容许呈现负余额。为了达到这个目标,咱们这次要应用set处理程序/陷阱。

在下面的例子中,咱们告诉以后的余额和取款后的新余额,如果新的余额为正数,咱们也会告诉并停止取款操作。

const bankAccount = {
    balance: 2020,
    name: 'Georgy Glezer'
};

const handler = {
    set: function (obj, prop, value) {
        console.log(`Current Balance: ${obj.balance}, New Balance: ${value}`);

        if (value < 0) {
            console.log(`We don't allow Negative Balance!`);
            return false;
        }
        obj[prop] = value;

        return true;
    }
};

const wrappedBankAcount = new Proxy(bankAccount, handler);

wrappedBankAcount.balance -= 2000; // access to the balance
console.log(wrappedBankAcount.balance);

wrappedBankAcount.balance -= 50; // access to the balance
console.log(wrappedBankAcount.balance);

// OUTPUT:
// Current Balance: 2020, New Balance: 20
// 20
// Current Balance: 20, New Balance: -30
// We don't allow Negative Balance!
// 20

咱们应用的是set operator/trap,它是一个返回布尔值(true/false)的函数,用来判断更新操作是否胜利。它接管以下参数。

  • target: 被拜访的对象(咱们封装的对象)。
  • prop:正在拜访的对象(咱们封装的对象)。在咱们的例子中,被拜访的属性是 “balance”。
  • value。应该更新的新值。
  • receiver*: 原先被调配到的对象。这通常是代理自身。但set()处理程序也能够通过原型链或其余各种形式间接调用。

你能够看到,它其实和get很类似,但只是多接管了1个新值的参数。

这2个操作符/陷阱是最常见的,如果你有趣味找到所有现有的操作符/陷阱,你能够查看这里。

谁应用代理

许多风行的库都应用了这种技术,例如: * [MobX]()

  • MobX
  • Vue
  • Immer

还有更多……他们中的大多数人都利用了Proxies给咱们带来的惊人力量,并为咱们提供了很棒的库。

应用案例和示例

咱们曾经看到,咱们能够应用代理服务器来进行。

  • 记录(告诉银行)
  • 验证(阻止正数余额更新)

缓存

咱们将再次应用get操作符/陷阱,并将 “dollars “属性增加到咱们的对象中。在每次拜访 “dollars “属性时,咱们将计算咱们的余额价值多少美元。因为计算是一个沉重的操作,所以咱们心愿尽可能的Cache它。

const bankAccount = {
    balance: 10,
    name: 'Georgy Glezer',
    get dollars() {
        console.log('Calculating Dollars');
        return this.balance *3.43008459;
    }
};

let cache = {
    currentBalance: null,
    currentValue: null
};

const handler = {
    get: function (obj, prop) {
        if (prop === 'dollars') {
            let value = cache.currentBalance !== obj.balance ? obj[prop] : cache.currentValue;

            cache.currentValue = value;
            cache.currentBalance = obj.balance;

            return value;
        }

        return obj[prop];
    }
};

const wrappedBankAcount = new Proxy(bankAccount, handler);

console.log(wrappedBankAcount.dollars);
console.log(wrappedBankAcount.dollars);
console.log(wrappedBankAcount.dollars);
console.log(wrappedBankAcount.dollars);

// OUTPUT:
// Calculating Dollars
// 34.3008459
// 34.3008459
// 34.3008459
// 34.3008459

正如你在例子中所看到的,咱们有一个缓存对象,它保留着以后的银行余额和以美元为单位的余额价值。每次有人拜访”_dollars”_属性时,咱们都会先进行计算,而后将其缓存起来。

DOM操作

咱们想在每次余额发生变化时更新屏幕上的文字。咱们将应用一个set操作符/陷阱,在每次扭转数值时,咱们将更新屏幕上的DOM元素。

const bankAccount = {
  balance: 2020,
  name: "Georgy Glezer",
  get text() {
    return `${this.name} Balance Is: ${this.balance}`;
  }
};

const objectWithDom = (object, domId) => {
  const handler = {
    set: function (obj, prop, value) {
      obj[prop] = value;

      document.getElementById(domId).innerHTML = obj.text;

      return true;
    }
  };

  return new Proxy(object, handler);
};

// create a dom element with id: bank-account
const wrappedBankAccount = objectWithDom(bankAccount, "bank-account");

wrappedBankAccount.balance = 26;
wrappedBankAccount.balance = 100000;

在这里,咱们创立了一个辅助函数,这样咱们就能够存储DOM元素的ID,并在set operator/trap中增加了简略的行来更新DOM元素。很简略,对吧?让咱们看看后果:)

概要

综上所述,咱们理解了ECMAScript 6 Proxies,咱们如何应用它们,以及用于什么目标。在我看来,Proxies是一个很神奇的工具,你能够用它来做各种各样的抉择,你只须要想想什么最适宜你:) 。

如果您喜爱这篇文章,欢送关注并拍手????。

资源简介

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理