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

40次阅读

共计 4178 个字符,预计需要花费 11 分钟才能阅读完成。

明天咱们要学习的是 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 是一个很神奇的工具,你能够用它来做各种各样的抉择,你只须要想想什么最适宜你:)。

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

资源简介

正文完
 0