Skip to content

我可以在JavaScript中创建动态的setter和getter吗?

有时,在使用对象时,数据的形状并不总是已知的。如果对象非常大,为每个属性添加特殊的getter可能也是低效的。此外,如果键名遵循某种模式,那么可能会有无限的潜在键名,通过使用setter无法验证其值。

这些只是一些可能用到动态setter和getter的用例。幸运的是,JavaScript的Proxy对象可以用于此目的。使用getset陷阱,我们可以在访问或设置属性时操作对象的行为。在本文中,我们将看两个简单的示例,以便让您了解其工作原理。

请注意,与这些示例相反,Proxy对象可以定义多个陷阱来拦截目标对象上的许多不同操作。

动态getter

动态getter是一个在属性上没有显式定义的getter,而是在访问属性时动态创建的。当数据的形状事先不知道,或者需要在返回之前操作属性的值时,这特别有用。

在这个示例中,我们将创建一个代理对象,用于操作目标对象中的字符串值。代理对象将修剪任何访问的字符串值,并对其他类型的值原样返回。最后,不存在的属性将返回undefined,如预期的那样。

const obj = { foo: 'bar  ', baz: '  qux ', quux: 1 };

const proxiedObj = new Proxy(obj, {
  get(target, prop) {
    if (prop in target && typeof target[prop] === 'string')
      return target[prop].trim();
    return target[prop];
  }
});

proxiedObj.foo; // 'bar'
proxiedObj.baz; // 'qux'
proxiedObj.quux; // 1
proxiedObj.quuz; // undefined

虽然这只是一个简单的例子,但它突出了Proxy对象的强大之处。在这种情况下,我们能够在不为每个属性定义getter的情况下操纵对象的行为。这也适用于添加到对象的任何新属性,因为代理将能够拦截访问并返回适当的值。

动态设置器

动态设置器是指在属性上没有明确定义的设置器,而是在设置属性时动态创建的。如果对象的键遵循某种模式或所有设置的值都满足某些条件,这将非常有用。

在这个例子中,我们将创建一个代理,只允许设置与格式yyyy-mm-dd相对应的日期属性。此外,如果属性已经设置,其值应该无法更改。例如,如果您正在创建类似只读日志的东西,这可能非常有用。

const obj = {};

const proxiedObj = new Proxy(obj, {
  set(target, prop, value) {
    if (prop in target) return false;
    if (typeof prop === 'string' && prop.match(/^\d{4}-\d{2}-\d{2}$/)) {
      target[prop] = value;
      return true;
    }
    return false;
  }
});

proxiedObj['2023-01-01'] = 1;
proxiedObj['2023-01-01'] = 2; // 这将失败,属性已经设置
proxiedObj['2023-ab-cd'] = 1; // 这将失败,属性名称不是日期
proxiedObj; // { '2023-01-01': 1 }

如此示例所示,Proxy对象可以用于在设置属性时验证键和值。在这种情况下,我们能够阻止属性的值被更改,以及阻止设置不符合预期模式的属性。

顺便提一下,记住这里使用的正则表达式不是完整的日期验证,而只是检查一个简单的模式来演示这个概念。如果您需要在生产环境中验证日期,这不是正确的方法。

结论

如本文所示,Proxy对象提供了一种特别强大的方式来操作对象的行为。话虽如此,在使用这个工具之前,你可能需要考虑一下你的具体用例。动态的getter和setter可以非常有用,但如果使用不当也可能会带来很多麻烦。