【问题标题】:Returning ES6 Proxy from the ES6 class constructor从 ES6 类构造函数返回 ES6 代理
【发布时间】:2017-04-19 02:37:56
【问题描述】:

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

例如

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

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

一种方法是使用new Proxy 而不是new Row,但是我们将失去我们在Row 类中所做的所有很酷的事情。我希望new Rowthis 引用作为代理目标返回一个代理对象。

有人对此有任何想法吗?如果你知道mongoosemongoose 是怎么做到的?

【问题讨论】:

  • 您能更详细地描述您要解决的问题吗?您似乎在描述一些可能的解决方案(使用代理),但并没有真正描述您要完成的工作。

标签: javascript proxy es6-class es6-proxy


【解决方案1】:

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

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

MDN: set 方法应该返回一个布尔值。返回真表示 那项任务成功了。如果 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 : 'john@doe.com'
});

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

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

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

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

【讨论】:

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

您完全可以在不使用代理的情况下做到这一点。

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

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() 页面上找到有关如何使用它的更多信息。

【讨论】:

  • 我的愿望是允许观察对象和数组属性运算符。这意味着任何所有未知名称。在构造函数中返回 Proxy 使之成为可能,而按名称定义属性则不行。
  • 使用它,新定义的属性可以立即在类构造函数或方法中使用。另一方面,如果您在类构造函数中返回 Proxy 对象,则代理的属性/方法仅在对象完全实例化后才可用。这是一个非常显着的限制,因为在 imo 中,类构造函数或方法引用自身或将“this”关键字链接为参数是很常见的。
【解决方案3】:

一个相关问题:

更多详情:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

最初的想法是我需要一门课,后来我意识到下面是我需要的:

const getObject = () => new Proxy({}, { get: (o, k) => k in o ? o[k] : 0 });

用法:

let o1 = getObject();
let o2 = getObject();

【讨论】:

    猜你喜欢
    • 2016-09-16
    • 1970-01-01
    • 1970-01-01
    • 2017-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-25
    • 2015-12-01
    相关资源
    最近更新 更多