如何在解构嵌套JavaScript对象时覆盖默认(对象)值

abithluo  于 2023-01-16  发布在  Java
关注(0)|答案(2)|浏览(119)

我正在尝试创建一个JavaScript类,它将一个对象作为它的唯一参数。对象属性应该与类本身定义的一些默认值合并(然后被用作类字段)。到目前为止,我使用对象解构来实现我想要做的事情--当对象只有一层深时效果很好。一旦我使用嵌套对象,我就不能覆盖“parent”属性(不传递嵌套对象)。
对象解构是我想要做的事情的正确方法吗?
类本身如下所示

class Class {
    constructor( args = {} ) {
        this.prop1 = {}; 

        ( {
            type: this.type = 'default',
            prop1: {
                value1: this.prop1.value1 = 'one',
                value2: this.prop1.value2 = 'two',
                value3: this.prop1.value3 = 'three'
            } = this.prop1
        } = args );
    }
}

预期

使用以下调用创建新类时

new Class( { type: 'myclass', prop1: { value1: 1 } } );

类字段被正确分配,并且类具有以下结构:

{
    type: 'myclass',
    prop1: {
        value1: 1,
        value2: 'two',
        value3: 'three'
    }
}

很完美也正是我想要的。

意外

当我想用期望的值/结构覆盖一些字段时,这就变得枣手了。像下面这样的新类创建“失败”,因为输入值被默认值覆盖了。
以下调用

new Class( { type: 'myclass', prop1: 'myProp1' } );

得到以下结构:

{
    type: 'myclass',
    prop1: {
        value1: 'one',
        value2: 'two',
        value3: 'three'
    }
}

这不是我想要的/我所期望的。我本来会期望下面的结构:

{
    type: 'myclass',
    prop1: 'myProp1'
}

是否有任何方法可以按照所描述的方式生成类-使用对象解构-或者它只是不合适的用例?
先谢了!

w7t8yxp5

w7t8yxp51#

我会避免使用可以是字符串或对象的属性,但是如果你真的需要它(不仅作为输入,而且作为结果类属性),你可以通过两次解构来实现:

class Class {
    constructor( args = {} ) {
        ( {
            type: this.type = 'default',
            prop1: this.prop1 = {},
        } = args );
        if (typeof this.prop1 == 'object') {
            ( {
                value1: this.prop1.value1 = 'one',
                value2: this.prop1.value2 = 'two',
                value3: this.prop1.value3 = 'three',
            } = this.prop1 );
        }
    }
}

(请注意,如果您传递一个对象,这确实会改变args.prop1!)
不过我会避免对对象属性进行解构,因为这相当少见(未知),而且看起来也不太好。

class Class {
    constructor(args) {
        this.type = args?.type ?? 'default',
        this.prop1 = args?.prop1 ?? {};
        if (typeof this.prop1 == 'object') {
            this.prop1.value1 ??= 'one',
            this.prop1.value2 ??= 'two',
            this.prop1.value3 ??= 'three',
        }
    }
}

(This如果你传递一个对象,仍然会改变args.prop1!而且它对待null值的方式也不同)
或者如果你真的想用解构的方法

class Class {
    constructor({type = 'default', prop1 = {}} = {}) {
        this.type = type;
        if (typeof prop1 == 'object') {
            const {value1 = 'one', value2 = 'two', value3 = 'three'} = prop1;
            this.prop1 = {value1, value2, value3};
        } else {
            this.prop1 = prop1;
        }
    }
}

(This始终创建一个不同于args.prop1的新this.prop1对象)

41zrol4v

41zrol4v2#

如果我在检查你的代码,我会让你修改它。我从来没有见过像这样使用反结构来设置另一个对象的值。这非常奇怪和难闻...但我知道你想做什么。
在最简单的情况下,我建议在这个场景中使用Object.assign,这允许您以您想要的方式合并多个对象(注意它是多么容易阅读):

const DEFAULTS = {
   type: 'default',
   prop1: {
       value1: 'one',
       value2: 'two',
       value3: 'three'
   }
}

class SomeClass {
  constructor( args = {} ) {
    Object.assign(this, DEFAULTS, args);
  }
}

这只会合并顶层属性。如果你想合并嵌套很深的对象,你需要手工操作,或者使用deepmerge这样的工具。下面是一个手工操作的例子(虽然不太容易阅读,但它仍然是非常普通的代码):

class SomeClass {
  constructor( args = {} ) {
    Object.assign(this, {
      ...DEFAULTS,
      ...args,
      prop1: typeof args.prop1 === 'string' ? args.prop1 : {
        ...DEFAULTS.prop1,
        ...args.prop1
      }
    });
  }
}

相关问题