如何修改构造函数以使其返回阻止向对象添加新属性的代理?

问题描述 投票:0回答:2

我希望用户只为对象设置特定属性,但同时该对象应该从自定义类构造。

例如

var row = new Row({
  name : 'John Doe',
  email : '[email protected]'
}, Schema);

row
可以有方法。但是当用户尝试设置
row.password
时,他们是不允许的。

一种方法是使用

new Proxy
而不是
new Row
但这样我们就会失去在
Row
类中所做的所有很酷的事情。我希望
new Row
返回一个以
this
引用作为代理目标的代理对象。

有人对此有什么想法吗?如果您知道

mongoose
mongoose
是如何做到的?

javascript es6-class es6-proxy
2个回答
43
投票

如果代理肯定会发生在您身上,限制设置功能的一种可能的解决方案是返回 ES6 代理实例。

默认情况下,JavaScript 中的构造函数会自动返回

this
对象,但您可以通过在
this
上实例化代理作为目标来定义并返回自定义行为。请记住,代理中的 set 方法应该返回一个布尔值。

MDN:set 方法应该返回一个布尔值。返回true表示 该任务成功了。如果 set 方法返回 false,并且 赋值发生在严格模式代码中,将会抛出 TypeError。

class Row {
  constructor(entry) {
    // some stuff

    return new Proxy(this, {
      set(target, name, value) {
        let setables = ['name', 'email'];
        if (!setables.includes(name)) {
          throw new Error(`Cannot set the ${name} property`);
        } else {
          target[name] = value;
          return true;
        }
      }
    });
  }

  get name() {
    return this._name;
  }
  set name(name) {
    this._name = name.trim();
  }
  get email() {
    return this._email;
  }
  set email(email) {
    this._email = email.trim();
  }
}

所以,现在不允许你根据代理设置不可设置的属性。

let row = new Row({
  name : 'John Doe',
  email : '[email protected]'
});

row.password = 'blahblahblah'; // Error: Cannot set the password property

也可以在 get 方法上有自定义行为。

但是,请注意并注意覆盖返回到调用上下文的引用。

注意: 示例代码已在 Node v8.1.3 和现代浏览器上进行了测试。


18
投票

您可以在不使用代理的情况下完成此操作。

在类构造函数中,您可以像这样定义密码属性:

constructor(options, schema) {
    this.name = options.name;
    this.email = options.email;
    Object.defineProperty(this, 'password', {
        configurable: false, // no re-configuring this.password
        enumerable: true, // this.password should show up in Object.keys(this)
        value: options.password, // set the value to options.password
        writable: false // no changing the value with this.password = ...
    });
    // whatever else you want to do with the Schema
}

您可以在 MDN 的

Object.defineProperty()
页面上找到有关如何使用此功能的更多信息。

© www.soinside.com 2019 - 2024. All rights reserved.