在 JavaScript 中,如何有条件地向对象添加成员?

IT技术 javascript
2021-01-21 20:59:29

我想创建一个有条件添加成员的对象。简单的方法是:

var a = {};
if (someCondition)
    a.b = 5;

现在,我想写一个更地道的代码。我在尝试:

a = {
    b: (someCondition? 5 : undefined)
};

但现在,ba其值为的成员undefined这不是想要的结果。

有方便的解决方案吗?

更新

我寻求一种解决方案,可以处理多个成员的一般情况。

a = {
  b: (conditionB? 5 : undefined),
  c: (conditionC? 5 : undefined),
  d: (conditionD? 5 : undefined),
  e: (conditionE? 5 : undefined),
  f: (conditionF? 5 : undefined),
  g: (conditionG? 5 : undefined),
 };
6个回答

我认为@InspiredJW 是用 ES5 做到的,正如@trincot 指出的那样,使用 es6 是一种更好的方法。但是我们可以通过使用扩展运算符和逻辑 AND 短路评估来添加更多的糖:

const a = {
   ...(someCondition && {b: 5})
}
@AlanH 扩展运算符就像是 的简写,Object.assign并且比 && 运算符具有更低的优先级。它忽略没有属性的值(布尔值、空值、未定义、数字),并...在就地之后添加对象的所有属性请记住,&&如果为真,运算符返回正确的值,否则为假。所以如果someCondition为真,{b : 5}将被传递给...运算符,从而将属性添加bawith value 5issomeCondition为假,false将传递给...运算符。导致没有添加任何内容。它很聪明。我喜欢它。
2021-03-11 20:59:29
我不太确定这是正确的,提案指出Null/Undefined Are Ignored,并没有说false被忽略了。转译器目前可能允许这样做,但它是否合规?以下应该是{...someCondition ? {b: 5} : null}但不是那么紧凑。
2021-03-15 20:59:29
很好的答案,但是将条件和结果对象放在括号中将大大提高此示例的可读性。并不是每个人都牢记 JS 运算符的优先级。
2021-03-19 20:59:29
我问这对提出传播建议的人是否有效,他们说这很好。github.com/tc39/proposal-object-rest-spread/issues/45,抄送@BenjaminDobell
2021-03-25 20:59:29
唯一的另一个问题是您不能将其用于 false 布尔值。
2021-04-06 20:59:29
const obj = {
   ...(condition) && {someprop: propvalue},
   ...otherprops
}

现场演示:

const obj = {
  ...(true) && {someprop: 42},
  ...(false) && {nonprop: "foo"},
  ...({}) && {tricky: "hello"},
}

console.log(obj);

虽然此代码片段可能会解决问题,但包括解释确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而那些人可能不知道您提出代码建议的原因。
2021-03-11 20:59:29
简短的解释是这样的:“...”展开运算符解构对象文字并将其添加到“obj”例如在这种情况下...(true) && {someprop: 42},要解构的整个术语是"(true) && {someprop: 42}",在这种情况下,布尔值为真,该术语只产生 {someprop:42},然后将其解构并添加到 obj 中。如果布尔值为假,则该术语将是假的,并且不会解构任何内容并将其添加到 obj 中
2021-03-17 20:59:29
这个答案对Jamie Hill 2 年前的答案有何补充
2021-03-22 20:59:29
这有效,并且它的语法比 IMO 的任何其他答案都好。
2021-04-02 20:59:29
@basickarl,不,出于前两条评论中提到的原因,它当然不应该是选定的答案。
2021-04-08 20:59:29

在纯 Javascript 中,我想不出比你的第一个代码片段更惯用的东西了。

但是,如果使用 jQuery 库不是不可能的,那么$.extend()应该满足您的要求,因为正如文档所说:

不复制未定义的属性。

因此,您可以编写:

var a = $.extend({}, {
    b: conditionB ? 5 : undefined,
    c: conditionC ? 5 : undefined,
    // and so on...
});

并获得您期望的结果(如果conditionBfalseb则将不存在于a)。

这实际上是一个错误的答案,因为它使用 jQuery 并且此三元条件不会从对象中删除属性,这只会将属性设置为未定义。请参阅@lagistos 答案以了解正确的方法,
2021-03-15 20:59:29
null 是否以同样的方式工作?还是必须是未定义的?
2021-03-17 20:59:29
@Andrew,这个答案需要 ES6,在我写我的时候不存在。
2021-03-31 20:59:29
@viebel,您是否有机会接受另一个答案而不是这个答案?
2021-04-02 20:59:29
有一种不需要 jQuery 的更好的方法。看看杰米希尔的回答。
2021-04-08 20:59:29

使用 EcmaScript2015,您可以使用Object.assign

Object.assign(a, conditionB ? { b: 1 } : null,
                 conditionC ? { c: 2 } : null,
                 conditionD ? { d: 3 } : null);

一些备注:

  • Object.assign 就地修改第一个参数,但它也返回更新的对象:因此您可以在更大的表达式中使用此方法来进一步操作对象。
  • 而不是null你可以通过undefinedor {},结果相同。您甚至可以提供0,因为原始值被包装,并且Number没有自己的可枚举属性

更简洁

进一步考虑第二点,您可以将其缩短如下(正如@Jamie 所指出的),因为虚假值没有自己的可枚举属性(false, 0, NaN, null, undefined, '', except document.all):

Object.assign(a, conditionB && { b: 1 },
                 conditionC && { c: 2 },
                 conditionD && { d: 3 });

我喜欢简化三元逻辑的速记。这正是我所需要的。谢谢!
2021-03-15 20:59:29
我更喜欢最初的解决方案:更容易弄清楚发生了什么——我不确定原始值会发生什么(至少在不查看规范的情况下不会)。
2021-04-07 20:59:29

我建议如下:

const a = {
   ...(someCondition? {b: 5}: {})
}
这比流行的答案更可靠。如果condition是一个对象,它会将其值注入到该对象中,这可能会导致错误。
2021-03-10 20:59:29
我喜欢那个 !谢谢!
2021-03-22 20:59:29
这个答案太棒了!用有条件地添加授权字段来获取 POST 参数的示例制作了一个要点:gist.github.com/mattlockyer/3dac7c9618ac98d16b046e32c364899d
2021-03-24 20:59:29