【问题标题】:How to enforce a strict class schema in ES6如何在 ES6 中强制执行严格的类模式
【发布时间】:2015-08-29 06:54:57
【问题描述】:

我是 es6 新手,想知道这种方法是否可行。我不希望有人在我的对象上设置我不想要的属性。

export default class User {

static getMembers() {
    return ['username','email','fullname','birthdate'];
}

constructor(props) {
    Object.keys(props).forEach((p)=>{
        if (User.getMembers().includes(p)) this[p]=props[p]
    });
    Object.defineProperty(this,"username",{writable:false});
    Object.defineProperty(this,"email",{writable:false});
}

还有其他方法吗?

【问题讨论】:

  • 使用上述方法,您无法为username 或email 设置任何值。它们将始终为 undefined,因为您已将它们设为只读且未为其分配值。
  • @T.J.Crowder 我确实在 defineProperty 通过构造函数运行之前为它们分配了一个值,然后它变得不可写。
  • 好吧,只要他们在props...
  • @T.J.Crowder:这似乎是预期的用法。我看不出有什么问题。
  • 虽然回答正是我所要求的,但我认为我没有很好地表达这个问题。我一直在寻找 Javascript 中是否存在一种模式,使对象的行为更像静态类型的 OOP 语言,除了类创建者想要的成员之外,您不能添加其他成员。对象密封不允许我们添加新属性,但如果它在“允许”列表中,我想添加一个。我应该为它提出一个新问题吗?

标签: javascript schema ecmascript-6


【解决方案1】:

您的代码如图所示,您不能为username 或email 设置任何值。它们将始终为undefined,因为您已将它们设置为只读并且没有为它们分配值。您也没有做任何事情来阻止代码访问这些对象之一设置完全任意的属性:

let u = new User();
x.anythingIWant = 42;

如果您想阻止代码向对象添加属性,您可以使用Object.seal(参考:MDN,spec)来实现,这会阻止添加新属性并且无法重新定义现有属性。所以:

export default class User {
    constructor() {
        // ...create your desired properties

        // Seal the object
        Object.seal(this);
    }
}

如果您还想将username 和email 设为只读,您还需要包含您拥有的Object.defineProperty 调用(之前Object.seal)。只要确保你先给它们赋值,一旦你完成了defineProperty和Object.seal,你就不能再改变它们了。

我想我可能会稍微不同地使用该白名单属性数组,只需遍历数组即可。

所以:

export default class User {
    static getMembers() {
        return ['username','email','fullname','birthdate'];
    }

    constructor(props) {
        // Create the properties
        User.getMembers().forEach((name) => { this[name] = props[name]; });

        // Make sure username and email have a value, because we won't
        // be able to change it in a moment
        // ...

        // Make username and email read-only
        Object.defineProperty(this, "username", {writeable: false});
        Object.defineProperty(this, "email", {writeable: false});

        // Seal the object
        Object.seal(this);
    }
}

【讨论】:

  • 但是确保我只在构造函数中设置我想要的属性可以使用这样的静态属性数组吗?
  • @arisalexis:如果你愿意,当然可以。不过,我想我可能会采取不同的做法:["username", "email", ...].forEach((name) => { this[name] = props[name]; })。不需要返回数组的方法(尽管它是无害的),也不需要使用includes。
  • @T.J.Crowder: User.getMembers() 是可覆盖的,而该数组文字并不那么容易访问。
  • @Bergi:确实——这两种方式都可以。 :-)(感谢您的修复。)
猜你喜欢
  • 2014-05-26
  • 1970-01-01
  • 2018-07-18
  • 2010-09-27
  • 1970-01-01
  • 2012-05-15
  • 2012-11-06
  • 2014-06-11
  • 2022-01-26
相关资源
最近更新 更多