在JavaScript中,我们一般适用对象来封装数据与行为,并通过浏览对象的属性去操作数据与执行行为。可是,在我们必须对特性浏览跟对象实际操作开展更粗粒度控制时,原生的目标体制很有可能也会变得不足灵便。比如,我们也许需要限定对象属性的载入和设定,或是纪录目标操控的日志,此刻Proxy
目标就能派上用场。
JavaScript里的Proxy
目标是ES6(ECMAScript 2015)引进的一个新特点,它允许创建一个代理对象,用以在目标用户的前提下提供一个额外抽象层。该代理对象允许阻拦和界定一些默认实际操作,比如特性浏览、函数调用、目标枚举类型等。Proxy
目标与Object.defineProperty()
方法与getter和setter方式相近,但它提供了更多性能和更加好的支持定制性。
建立Proxy对象词法如下所示:
const proxy = new Proxy(target, handler);
在其中,target
提出要建立代理对象的目标用户,handler
是一个目标,它重新定义了要阻拦的操作。handler
目标能够包括一组特殊方式,这个方法允许阻拦并界定默认实际操作,比如get()
、set()
、apply()
等。
以下属于一些可利用的方式:
get(target, prop, receiver)
:阻拦对象属性的载入实际操作。set(target, prop, value, receiver)
:阻拦对象属性设置实际操作。has(target, prop)
:阻拦目标in操作符的操作。apply(target, thisArg, argumentsList)
:阻拦函数的调用实际操作。construct(target, argumentsList, newTarget)
:阻拦new运算符的操作。getOwnPropertyDescriptor(target, prop)
:阻拦Object.getOwnPropertyDescriptor()的操作。defineProperty(target, prop, descriptor)
:阻拦Object.defineProperty()的操作。deleteProperty(target, prop)
:阻拦对象属性的移除实际操作。getPrototypeOf(target)
:阻拦Object.getPrototypeOf()的操作。setPrototypeOf(target, prototype)
:阻拦Object.setPrototypeOf()的操作。isExtensible(target)
:阻拦Object.isExtensible()的操作。preventExtensions(target)
:阻拦Object.preventExtensions()的操作。enumerate(target)
:阻拦for...in循环的操作。ownKeys(target)
:阻拦Object.getOwnPropertyNames()和Object.getOwnPropertySymbols()的操作。
每一个方式函数公式都能被传送一些主要参数,包含目标用户、属性名、值等。我们可以在函数中解决这些主要参数,随后回到你最期待的结果。
下列是一个应用Proxy
目标的事例,用以纪录对象属性的载入和设定实际操作:
const target = {
name: 'John',
age: 30
};
const handler = {
get: function(target, prop, receiver) {
console.log(`Getting ${prop} value`);
return target[prop];
},
set: function(target, prop, value, receiver) {
console.log(`Setting ${prop} value to ${value}`);
target[prop] = value;
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // 导出 "Getting name value" 和 "John"
proxy.age = 40; // 导出 "Setting age value to 40"
console.log(proxy.age); // 导出 "Getting age value" 和 "40"
在后面的例子中,使用Proxy
目标创建了一个代理对象proxy
,它代理商了目标用户target
的载入和设定实际操作。在handler
目标中,大家重新定义了get()
和set()
方式来阻拦载入和设定实际操作,做好记录了操控的日志。在代理对象上载入和设定特性时,我们会看到对应的日志导出。
除了以上的办法,Proxy目标还提供一些其他的特点,比如“可撤销代理商”。可撤销代理商是一种专项计划的代理对象,它允许撤消代理对象的操作并复原到初始目标。我们可以通过启用Proxy.revocable()
方式来创建一个可撤销代理对象。
下列是一个应用可撤销代理商的事例:
const target = { name: 'John', age: 30 };
const handler = {
get: function(target, prop) {
return target[prop];
}
};
const {proxy, revoke} = Proxy.revocable(target, handler);
console.log(proxy.name); // 导出 "John"
revoke(); // 撤消代理对象
console.log(proxy.name);
// 抛出去 TypeError: Cannot perform 'get' on a proxy that has been revoked
在后面的例子中,使用Proxy.revocable()
方式创建了一个可撤销代理对象。我们能像一般代理对象一样使用这些,可是在我们启用revoke()
方式撤消代理对象时,每一个实际操作要被复原到初始目标上。在这样一个例子中,大家在撤消代理对象后重新浏览代理商对象的属性,会提出一个TypeError
出现异常。
总而言之,Proxy
目标是一个强劲且灵便的特点,它能让你以一种非常粗粒度的形式被控对象的浏览及使用,同时提供了很多有意思和有价值的作用。尽管应用Proxy
目标一定要谨慎,但当你必须能够更好地被控对象状况时,它是一个非常有使用价值的一种手段。