问题 从ES6类构造函数返回ES6代理


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

例如

var row = new Row({
  name : 'John Doe',
  email : 'uhiwarale@gmail.com'
}, Schema);

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

一种方法是使用 new Proxy 代替 new Row 但是我们将放弃我们正在做的所有酷事 Row 类。我想要 new Row 返回一个代理对象 this 引用作为代理的目标。

有人对此有什么想法吗?如果你知道的话 mongoose, 怎么样 mongoose 这样做?


7889
2017-12-04 18:00


起源

你能描述一下你想要解决的问题吗?您似乎在描述一些可能的解决方案(使用代理),但并没有真正描述您要完成的任务。 - jfriend00


答案:


如果确定代理发生了,则限制集合功能的一种可能解决方案是返回ES6代理实例。

默认情况下,javascript中的构造函数返回 this 自动对象,但您可以通过实例化代理来定义和返回自定义行为 this 作为目标。请记住,代理中的set方法应返回一个布尔值。

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

class Row {
  constructor(entry, schema) {
    // 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 name(email) {
    this._email = email.trim();
  }
}

因此,现在不允许根据代理设置非setable属性。

let row = new Row({
  name : 'John Doe',
  email : 'john@doe.com'
}, Schema);

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

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

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

注意: 示例代码已在Node v8.1.3上进行了测试


8
2017-07-26 04:07



错误:“意外令牌新”?!我不认为你可以在构造函数中使用'new',它也不喜欢“return Proxy”? - Master James
哇它看起来好像有用吗?!尼斯。似乎构造函数在其他尝试中没有返回新的Proxy,所以感谢这个例子。 - Master James
@MasterJames不用担心。是的,它适用于Node v8.1.3。 - hallaji
从构造函数返回代理的一个潜在问题是,这会以与用户受限相同的方式限制您的代码,即您的业务逻辑在构造后无法设置或更新实例上的其他属性。解决这个问题的一种方法是使用a来代理类本身 handler.construct 包装和限制返回给用户的实例的方法,但仍然允许您的代码访问底层实例。 - Joshua Skrzypek
为什么类构造函数的mdn页面(developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...)没有提到类构造函数可以返回对象?在哪里可以找到这种级别的信息? - junvar


您可以在不使用Proxies的情况下执行此操作。

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

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() 页。


5
2018-02-16 21:03



我的愿望是允许观察Object和Array属性操作符。这意味着任何未知名称。在构造函数中返回代理可以实现,按名称定义属性则不行。 - Master James