在较低级别使用JavaScript时,对这些构造有扎实的了解将非常方便。在本文中,我们将介绍一些适合这些构造的用例,它们肯定会为您带来一些便捷。
代理服务器
简单来说,代理服务器是控制对另一个对象的访问的对象。根据MDN文档【https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy】:
Proxy对象用于定义基本操作的自定义行为(例如,属性查找,赋值,枚举,函数调用等)。
该描述大致转化为一种思想,我们可以拦截对对象和函数的基本操作(例如,函数调用,属性查找,赋值,枚举等),并在运行时执行我们自己的自定义操作!太好了,是吗?
在继续之前,有三个与代理对象相关的关键术语:
处理程序 - 包含陷阱的占位符对象。
陷阱 - 提供属性访问的方法。这类似于操作系统中陷阱的概念。
目标 - 代理虚拟化的对象。
如果使用正确,代理对象将强大地补充其目标对象。
创建代理
我们可以使用Proxy构造函数创建一个JavaScript Proxy — new Proxy().
Proxy构造函数接受两个对象作为参数。第一个是代理虚拟化的目标对象,第二个是处理程序对象,其中包含一组称为“陷阱”的方法。这些陷阱将控制对目标对象的属性访问:
const proxy = new Proxy(targetObject, handler);
我们可以通过将目标对象和空处理程序传递给Proxy构造函数来创建一个简单的Proxy对象:
const targetObj = {name: 'Target'}; const proxy = new Proxy(targetObj, {}); proxy.name; // returns 'Target'
我们上面定义的Proxy对象目前对目标对象没有任何作用。它只是将对“ name”属性的请求传递给目标对象。为了在代理服务器上为其目标定义一个或多个自定义行为,我们将需要声明一个或多个处理程序。
这种处理程序之一是get
陷阱处理程序。下面的示例截取对目标对象的属性的“ getter”调用:
const data = { firtName: 'Bryan', lastName: 'John' }; const handler = { get(target, prop) { return prop in target ? target[prop] : 'This property doesn’t exist, sorry'; } }; const proxy = new Proxy(data, handler); console.log(proxy.firstName); // Returns 'Bryan' console.log(proxy.age); // Returns 'No such property'
在上面的代码中,我们有handler
一个包含get
陷阱的对象。该get
陷阱截获请求访问的目标对象,由代理对象进行,并返回(如果可用)或请求的财产“这个属性不存在,对不起”,如果它不是。
如果我们想拦截在对象上设置属性的调用,则需要使用set
陷阱。
让我们看一个更有用的例子。我们将使用set
陷阱检查actualPay
对象的属性是否已设置。如果存在此物业,我们将从所支付的金额中扣除3%作为交易费,并将新值分配给该actualPay
物业:
const transaction = {}; const handler = { set(target, prop, value) { if(prop === 'actualPay' && typeof value === "number" && value > 0) { value = value * 0.97; } target[prop] = value; } }; const proxy = new Proxy(transaction, handler); proxy.actualPay = 1000; console.log(proxy.actualPay); //Returns '970'
用例范例
代理的好处是您不需要事先知道或定义属性。这与ES5获取器/设置器相反,后者要求事先提供属性:
const data = { _firstName: 'John', _lastName: 'Doe', get firstName() { console.log('getting the firstname: ', this._firstName); }, get lastName() { console.log('getting the lastname: ', this._lastName); }, }; data.firstName; //logs -> getting the firstname: John data.lastName; //logs -> getting the firstname: Doe
在上面的示例中,我们getters
为firstname和lastname属性定义了。然而,如果我们增加了新的特性- age
-我们需要定义一个新的getter - get age()
-上data
对象访问属性:
data.age = 23; // adds a new property -- age console.log(data.age); // logs 23 but doesn't automatically have a getter
使用代理,我们可以简单地get
为所有访问对象属性的请求注册一个陷阱,包括那些在编写时没有声明的请求:
const proxyObj = new Proxy({ firstName: 'John', lastName: 'Doe', }, { get(targetObj, property) { console.log(`getting the ${property} property: ${targetObj[property]}`); } }); proxyObj.firstName; //Returns -> getting the firstName: John proxyObj.lastName;// Returns -> getting the lastName property: Doe proxyObj.age = 23; console.log(proxyObj.age);// Returns -> getting the age property: 23
在上面的示例中,我们能够使用Proxy记录对象上所有属性的值。
代理可以满足更多的用例,例如,我们可以创建一个自定义对象验证器,该验证器检查对象的属性以确保只能将预期类型设置为值。
我们还可以创建一个自定义身份验证系统,以确保授权客户端对目标执行操作。可能性是无止境!
代理的其他一些可能的用例是:
条件缓存
属性查询扩展
价值修正
调试
生成器
当调用一个函数时,JavaScript引擎开始从函数顶部到底部执行代码。这种执行模型称为“ 运行到完成”,当您希望函数按定义运行时,它非常有用。
但是,有时您希望暂停函数的执行,运行其他代码段,然后从上次中断的地方继续执行。发电机就是这个愿望的答案!
什么是生成器?
简而言之,生成器是一种可以在中途停止然后从停止处继续运行的功能。
让我们考虑一个类比-想象一下,您正在一天的待办事项列表中工作,而老板礼貌地要求您立即进行其他工作。我敢打赌,按照以下五个步骤,您的下一个操作将是:
隐式记住您在“待办事项”列表上的位置。
抱怨老板的事,随意踢椅子。
处理老板刚刚分配给您的任务。
返回您的办公桌,然后从您在“待办事项”列表上停下来的位置继续。
检查您的手腕,看看是否是下午5点,您错过了新的副业项目,该项目肯定将成为一家市值十亿美元的公司。
您的行为就像一个生成器函数!我的意思是,除了第2点和第5点。生成器函数可以暂停其执行,运行其他操作,并记住执行时在何处暂停,然后从那里继续。
生成器函数是ES6构造,可以简化JavaScript应用程序的异步控制流,同时隐式维护其内部状态。调用生成器函数时,在执行该函数的代码之前,它首先创建一个称为生成器的迭代器对象。根据ECMAScript规范,此生成器对象:
是生成器函数的实例,并同时符合Iterator和Iterable接口。
Iterable协议在指定如何使用for..of
构造迭代对象中的值时提供了很大的灵活性。迭代器协议为对象中的值定义了一种标准方法。可以使用.next()
本文稍后将看到的方法来实现迭代。
信息:异步/等待构造基于生成器。
使用生成器
生成器函数是使用function*
语法创建的。它的值是通过调用next()
方法生成的,可以使用yield
关键字暂停执行。每次调用该函数时,它都会返回一个新的Generator对象,该对象可以迭代一次:
function* getCurrency() { console.log('the generator function has started'); const currencies = ['NGN', 'USD', 'EUR', 'GBP', 'CAD']; for (const currency of currencies) { yield currency; } console.log('the generator function has ended'); } const iterator = getCurrency(); console.log(iterator.next()); // logs -> 'the generator function has started' // {value: 'NGN', done: false} console.log(iterator.next()); // {value: 'USD', done: false} console.log(iterator.next()); //{value: 'EUR', done: false} console.log(iterator.next()); //{value: 'GBP', done: false} console.log(iterator.next()); //{value: 'CAD', done: false} console.log(iterator.next()); // the generator function has ended // {value: undefined, done: true}
在上面的示例中,生成器函数getCurrency()
使用yield
关键字发送数据。next()
在生成器对象上调用该方法将返回其yield
值和一个布尔值— done
— true
在迭代生成器函数的所有值之后变为Boolean ,如上例中的上一次迭代所示。
我们还可以使用该next()
方法将数据传递给生成器函数
function* displayCurrrency() { console.log(`currency info to be sent into the generator function: ${yield}`); } const iterator = displaycurrency(); iterator.next(); //this starts the generator function iterator.next('US dollars'); // logs -> currency info to be sent into the generator function: US dollars
在上面的示例中,next('US dollars')
将数据发送到生成器函数,并用“ yield
美元”“替换” 关键字。
总结
我们已经了解了JavaScript代理以及它们如何控制和自定义JavaScript对象的行为。我们还看到,生成器对象可以将数据发送进出其生成器函数。
如果使用正确,这些ES6构造可以大大改善代码体系结构和设计。
网友评论文明上网理性发言 已有0人参与
发表评论: