JavaScript代理对象的使用方法

96 阅读2分钟

在处理对象时,我们可以创建一个代理对象,拦截并改变一个现有对象的行为。

我们使用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 当我们试图设置一个属性时被执行

等等。基本上,我们可以创建一个控制对象上发生的一切的防护门,并提供额外的规则和控制来实现我们自己的逻辑。

我们可以使用的其他方法(也叫陷阱)有。

  • enumerate
  • getOwnPropertyDescriptor
  • getPrototypeOf
  • has
  • isExtensible
  • ownKeys
  • preventExtensions
  • setPrototypeOf

都与各自的功能相对应。

你可以在MDN上阅读更多关于每一个的内容

让我们用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 对象上删除属性,但如果你写你的逻辑,使该对象无法访问,你只暴露代理,这是一种封装你的逻辑的方法。