【问题标题】:Assign ES6 class constructors to 'this' without repeating variable names [duplicate]将 ES6 类构造函数分配给“this”而不重复变量名 [重复]
【发布时间】:2018-07-10 20:12:22
【问题描述】:

在编写 ES6 类时,您可以在构造函数中使用解构,以便更轻松地使用默认选项:

class Person {
    constructor({
        name = "Johnny Cash",
        origin = "American",
        profession = "singer"
    } = {}) {
        this.name = name;
        this.origin = origin;
        this.profession = profession;
    }

    toString() {
        return `${this.name} is an ${this.origin} ${this.profession}`;
    }
}

这允许你做这样的事情:

const person = new Person();
console.log(person.toString());
// Returns 'Johnny Cash is an American singer'

const nina = new Person({
    name : "Nina Simone"
})
console.log(nina.toString());
// Returns 'Nina Simone is an American singer'

但是,您需要重复构造函数中的参数以将它们分配给类实例。我已经发现你可以这样做以减少冗长:

Object.assign(this, { name, origin, profession });

但是您仍然需要重复这三个变量。有什么方法可以在不重复变量的情况下使赋值更短?

【问题讨论】:

    标签: javascript ecmascript-6 es6-class


    【解决方案1】:

    你可以让你的构造函数接受一个“config”参数,然后说Object.assign(this, config)。要拥有默认值,您可以设置一个默认对象,或者在构造函数之外将它们分配为类属性。

    编辑给 T.J. Crowder 的观点,从技术上讲,在使用 Object.assign() 时传入的任何内容都将添加到您的对象中,这可能在很多方面都是有害的。我添加了一种方法来剥离配置对象,使其仅包含您定义的一组属性。 T.J. 的解决方案也可以,我只是做了不同的处理,所以你有选择。

    function stripObjToModel(model, obj) {
      // this method will modify obj
      Object.keys(obj).forEach(function (key) {
        if (!model.hasOwnProperty(key)) {
          delete obj[key];
        }
      });
      return obj;
    }
    class Person {
        constructor(config = {}) {
            var defaults = {
                name: "Johnny Cash",
                origin: "American",
                profession:  "singer"
            };
            Object.assign(this, defaults, stripObjToModel(defaults, config));
        }
    
        toString() {
            return `${this.name} is an ${this.origin} ${this.profession}`;
        }
    }
    
    const person = new Person();
    console.log(person.toString());
    // Returns 'Johnny Cash is an American singer'
    
    const nina = new Person({
        name : "Nina Simone",
        foo: "bar",
        toString: function () {return "Hello World!";}
    })
    console.log(nina.toString());
    // Returns 'Nina Simone is an American singer'

    【讨论】:

    • @T.J.Crowder 是的,那是我的错误 - 它已被修复
    • 像这样的Object.assign 解决方案让我困扰的是选项对象中的所有 属性都被复制到this,无论它们是name,@ 987654328@、profession 或其他名称(甚至可以是 toString)。
    • @T.J.Crowder 是的,也许我说错了——我认为比“应用”更好的词是“优先考虑”
    • @Husky 是的,我认为这是普遍共识 - 您的原始代码很好。这有点冗长,但我认为没有好的选择。
    • @T.J.Crowder 看看the spec,你是对的。从机械上讲,它是从左到右完成的。
    【解决方案2】:

    不是我提倡,但技术上你可以做到

    constructor(options = {}) {
      ({
        name: this.name = "Johnny Cash",
        origin: this.origin = "American",
        profession: this.profession = "singer",
      } = options);
    }
    

    我个人认为你的示例代码有点重复看起来很好。

    【讨论】:

    • 当我尝试运行它时,我得到一个Unexpected token this...
    • LOL - 仍然重复名称,不过。 :-) 而且你不能在子类中,this 在子类构造函数的参数范围内不可用。
    • @Husky:现在试试看(洛根有:,他的意思是=,有趣的是我在回答中犯的错误,他纠正了......)。
    • 我猜这个解决方案也有点没有实际意义,因为它再次重复了变量名。
    • 洛根 - 是的。和你一样,我认为@Husky 的原始代码是最好的方法。简单、清晰,没有太多重复。
    【解决方案3】:

    遗憾的是,我认为没有任何内置方法可以接受具有单独默认值的选项对象,并且只从您收到的对象中获取那些属性(而不是其他可能指定的外来属性)而不重复自己。这是不幸的。 (这也不是我第一次想要解构对被解构对象的引用。)

    这意味着我们必须自己出去,但这很简单:

    function applyDefaults(target, options, defaults) {
        for (const key in defaults) { // Or `const key of Object.keys(defaults)` for just own props
            target[key] = (typeof options[key] === undefined ? defaults : options)[key];
        }
    }
    

    然后:

    constructor(options = {}) {
        applyDefaults(this, options, {
            name: "Johnny Cash",
            origin: "American",
            profession: "singer"
        });
    }
    

    (如果在每个构造函数调用上重新创建对象让您担心,您可以将其移出类,但我不会担心。)

    但是然后在方法签名中没有描述单个属性默认值,对我来说这将是一个足够充分的理由继续重复你现在拥有的名称。

    【讨论】:

    • 是的,这也是一个不错的解决方案,如果我不会编写 ES6,我可能会如何处理它。但也许重复属性并没有我最初想的那么糟糕:至少它是明确的。
    • @Husky:是的,我会坚持你所拥有的。但如果你想要一个替代方案,这很简短,而且只列出一次名称。 ;-)
    猜你喜欢
    • 2019-07-15
    • 1970-01-01
    • 2019-07-21
    • 2015-12-01
    • 2019-06-29
    • 2022-01-18
    • 2016-12-02
    • 1970-01-01
    • 2018-08-01
    相关资源
    最近更新 更多