在处理对象时,我们可以创建一个代理对象,拦截并改变一个现有对象的行为。
我们使用ES2015中引入的Proxy本机对象来做这件事。
假设我们有一个car 对象。
const car = {
color: 'blue'
}
我们可以做的一个非常简单的例子是,当我们试图访问一个不存在的属性时,返回一个 "未找到 "的字符串。
你可以定义一个代理,每当你试图访问这个对象的一个属性时就会被调用。
你可以通过创建另一个具有get() 方法的对象来做到这一点,该方法接收目标对象和属性作为参数。
const car = {
color: 'blue'
}
const handler = {
get(target, property) {
return target[property] ?? 'Not found'
}
}
现在我们可以通过调用new Proxy() 来初始化我们的代理对象,传递原始对象和我们的处理程序。
const proxyObject = new Proxy(car, handler)
现在尝试访问一个包含在car 对象中的属性,但从proxyObject 中引用它。
proxyObject.color //'blue'
这就像调用car.color 。
但是当你试图访问一个在car 上不存在的属性时,比如car.test ,你会得到undefined 。使用代理,你会得到'Not found' 字符串,因为那是我们告诉它要做的。
proxyObject.test //'Not found'
我们并不局限于代理处理程序中的get() 方法。这只是我们能写的最简单的例子。
我们还有其他方法可以使用。
apply当我们在对象上使用 时被调用。apply()construct当我们访问对象的构造函数时被调用deleteProperty当我们试图删除一个属性时被执行defineProperty当我们在对象上定义一个新属性时被调用set当我们试图设置一个属性时被执行
等等。基本上,我们可以创建一个控制对象上发生的一切的防护门,并提供额外的规则和控制来实现我们自己的逻辑。
我们可以使用的其他方法(也叫陷阱)有。
enumerategetOwnPropertyDescriptorgetPrototypeOfhasisExtensibleownKeyspreventExtensionssetPrototypeOf
都与各自的功能相对应。
让我们用deleteProperty 来做另一个例子。我们想防止删除一个对象的属性。
const car = {
color: 'blue'
}
const handler = {
deleteProperty(target, property) {
return false
}
}
const proxyObject = new Proxy(car, handler)
如果我们调用delete proxyObject.color ,我们会得到一个TypeError。
TypeError: 'deleteProperty' on proxy: trap returned falsish for property 'color'
当然,人们总是可以直接在car 对象上删除属性,但如果你写你的逻辑,使该对象无法访问,你只暴露代理,这是一种封装你的逻辑的方法。