如何使用Proxy 来代理Js中的类?

来源:http://www.chinese-glasses.com 作者:Web前端 人气:180 发布时间:2020-04-29
摘要:时间: 2019-09-17阅读: 141标签: 代理 时间: 2019-07-07阅读: 199标签: Proxy什么是 Proxy Proxy 对象(Proxy)是 ES6的一个非常酷却鲜为人知的特性。虽然这个特性存在已久,但是我还是想在本文中对

时间: 2019-09-17阅读: 141标签: 代理

时间: 2019-07-07阅读: 199标签: Proxy什么是 Proxy

Proxy 对象(Proxy)是 ES6 的一个非常酷却鲜为人知的特性。虽然这个特性存在已久,但是我还是想在本文中对其稍作解释,并用一个例子说明一下它的用法。

通常,当谈到JavaScript语言时,我们讨论的是ES6标准提供的新特性,本文也不例外。 我们将讨论JavaScript代理以及它们的作用,但在我们深入研究之前,我们先来看一下Proxy的定义是什么。

什么是 Proxy

MDN上的定义是:代理对象是用于定义基本操作的自定义行为(例如,属性查找,赋值,枚举,函数调用等)。

正如 MDN 上简单而枯燥的定义:

换句话说,我们可以说代理对象是我们的目标对象的包装器,我们可以在其中操纵其属性并阻止对它的直接访问。 你可能会发现将它们应用到实际代码中很困难,我鼓励你仔细阅读这个概念,它可能会改变你的观点。

10bet,Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。

术语

虽然这是一个不错的总结,但是我却并没有从中搞清楚 Proxy 能做什么,以及它能帮我们实现什么。

handler:包含陷阱(traps)的占位符对象。

首先,Proxy 的概念来源于元编程。简单的说,元编程是允许我们运行我们编写的应用程序(或核心)代码的代码。例如,臭名昭著的 eval 函数允许我们将字符串代码当做可执行代码来执行,它是就属于元编程领域。

traps:提供属性访问的方法。这类似于操作系统中捕获器的概念。

Proxy API 允许我们在对象和其消费实体中创建中间层,这种特性为我们提供了控制该对象的能力,比如可以决定怎样去进行它的 get 和 set,甚至可以自定义当访问这个对象上不存在的属性的时候我们可以做些什么。

target:代理虚拟化的对象。(由代理对象包装和操作的实际对象)

Proxy 的 API

在本文中,我将为get和set陷阱 提供简单的用例,考虑到最后,我们将看到如何使用它们并包含更复杂的功能,如API。

var p = new Proxy(target, handler);

语法和用例

Proxy 构造函数获取一个 target 对象,和一个用来拦截 target 对象不同行为的 handler对象。你可以设置下面这些拦截项:

letp =newProxy(target, handler);

has— 拦截in操作。比如,你可以用它来隐藏对象上某些属性。

将目标和处理程序传递给Proxy构造函数,这样就创建了一个proxy对象。现在,让我们看看如何利用它。为了更清楚地看出Proxy的好处,首先,我们需要编写一些没有它的代码。

get— 用来拦截读取操作。比如当试图读取不存在的属性时,你可以用它来返回默认值。

想象一下,我们有一个带有几个属性的用户对象,如果属性存在,我们想要打印用户信息,如果不存在,则抛出异常。在不使用代理对象时,判断属性值是否存在的代码也放在了打印用户信息的函数,即printUser中(这并不是我们所希望的),如下demo所示:

set— 用来拦截赋值操作。比如给属性赋值的时候你可以增加验证的逻辑,如果验证不通过可以抛出错误。

let user = { name: 'John', surname: 'Doe'};let printUser = (property) = { let value = user[property]; if (!value) { throw new Error(`The property [${property}] does not exist`); } else { console.log(`The user ${property} is ${value}`); }}printUser('name'); // 输出: 'The user name is John'printUser('email'); // 抛出错误: The property [email] does not exist

apply— 用来拦截函数调用操作。比如,你可以把所有的函数调用都包裹在try/catch语句块中。

get

这只是一部分拦截项,你可以在 MDN 上找到完整的列表。

通过查看上面的代码,你会发现:将条件和异常移到其他地方,而printUser中仅关注显示用户信息的实际逻辑会更好。这是我们可以使用代理对象的地方,让我们更新一下这个例子。

下面是将 Proxy 用在验证上的一个简单的例子:

let user = { name: 'John', surname: 'Doe'};let proxy = new Proxy(user, { get(target, property) { let value = target[property]; if (!value) { throw new Error(`The property [${property}] does not exist`); } return value; }});let printUser = (property) = { console.log(`The user ${property} is ${proxy[property]}`);};printUser('name'); // 输出: 'The user name is John'printUser('email'); // 抛出错误: The property [email] does not exist
const Car = { maker: 'BMW', year: 2018,};const proxyCar = new Proxy(Car, { set(obj, prop, value) { if (prop === 'maker'  value.length  1) { throw new Error('Invalid maker'); } if (prop === 'year'  typeof value !== 'number') { throw new Error('Invalid year'); } obj[prop] = value; return true; }});proxyCar.maker = ''; // throw exceptionproxyCar.year = '1999'; // throw exception

在上面的示例中,我们包装了user对象,并设置了一个get方法。 此方法充当拦截器,在返回值之前,会首先对属性值进行检查,如果不存在,则抛出异常。

可以看到,我们可以用 Proxy 来验证赋给被代理对象的值。

输出与第一种情况相同,但此时printUser函数专注于逻辑,只处理消息。

使用 Proxy 来调试

set

为了在实践中展示 Proxy 的能力,我创建了一个简单的监测库,用来监测给定的对象或类,监测项如下:

代理可能有用的另一个例子是属性值验证。在这种情况下,我们需要使用set方法,并在其中进行验证。例如,当我们需要确保目标类型时,这是一个非常有用的钩子。我们来看一下实际使用:

函数执行时间

let user = new Proxy({}, { set(target, property, value) { if (property === 'name'  Object.prototype.toString.call(value) !== '[object String]') { // 确保是 string 类型 throw new Error(`The value for [${property}] must be a string`); }; target[property] = value; }});user.name = 1; // 抛出错误: The value for [name] must be a string

函数的调用者或属性的访问者

这些是相当简单的用例,以下场景,proxy均可以派上用场:

统计每个函数或属性的被访问次数。

格式化价值和类型修正数据绑定调试...

这是通过在访问任意对象、类、甚至是函数时,调用一个名为 proxyTrack 的函数来完成的。

现在是时候创建一个更复杂的用例了。

如果你希望监测是谁给一个对象的属性赋的值,或者一个函数执行了多久、执行了多少次、谁执行的,这个库将非常有用。我知道可能还有其他更好的工具来实现上面的功能,但是在这里我创建这个库就是为了用一用这个 API。

具有代理的API - 更复杂的示例

本文由10bet发布于Web前端,转载请注明出处:如何使用Proxy 来代理Js中的类?

关键词:

上一篇:纯css制作电闪雷鸣的天气图标

下一篇:没有了

最火资讯