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

Uda*_*ale 15 javascript proxy es6-proxy es6-class

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

例如

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

row可以有方法.但是当用户尝试设置时row.password,不允许这样做.

一种方法是使用new Proxy而不是new Row然后我们将放弃我们在Row课堂上做的所有很酷的事情.我想new Row返回一个代理对象this作为代理目标引用.

有人对此有什么想法吗?如果你知道mongoose,怎么mongoose做呢?

Vah*_*aji 17

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

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

MDN:set方法应该返回一个布尔值.返回true表示赋值成功.如果set方法返回false,并且赋值发生在strict-mode代码中,则抛出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();
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

row.password = 'blahblahblah'; // Error: Cannot set the password property
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 从构造函数返回代理的一个潜在问题是,这会以与用户受到限制相同的方式限制您的代码,即您的业务逻辑在构造实例后无法设置或更新实例上的其他属性。解决这个问题的一种方法是使用 [handler.construct](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/construct 来代理类本身) 方法来包装和限制返回给用户的实例,但仍然允许您的代码访问底层实例。 (3认同)
  • 为什么类构造函数的 mdn 页面(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor)没有提到类构造函数可以返回对象?在哪里可以找到这一级别的信息? (3认同)

Jos*_*pek 11

您可以在不使用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
}
Run Code Online (Sandbox Code Playgroud)

您可以在MDN Object.defineProperty()页面上找到有关如何使用它的更多信息 .