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

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

现在,我想写一个更习惯的代码。我在努力:

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

但是现在,b是a的一个元素,它的值是未定义的。这不是我们想要的结果。

有没有方便的解决办法?

更新

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

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),
 };

当前回答

使用增强对象属性并只设置为真值的属性,例如:

[isConditionTrue() && 'propertyName']: 'propertyValue'

因此,如果条件不满足,它不会创建首选属性,因此您可以丢弃它。 见:http://es6-features.org/ ComputedPropertyNames

更新: 最好遵循Axel Rauschmayer在他的博客文章中关于在对象字面量和数组中有条件地添加条目的方法(http://2ality.com/2017/04/conditional-literal-entries.html):)

const arr = [
  ...(isConditionTrue() ? [{
    key: 'value'
  }] : [])
];

const obj = {
  ...(isConditionTrue() ? {key: 'value'} : {})
};

对我帮助很大。

其他回答

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

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

未定义的属性不会被复制。

因此,你可以这样写:

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

并获得您期望的结果(如果条件b为假,则b将不存在于a中)。

下面的代码片段应该可以工作。

const a = {}

const conditionB = true;
const conditionC = true;
const conditionD = true;
const conditionE = true;

const b = {
  ...(conditionB && { b : 5}),
  ...(conditionC && { c : 5}),
  ...(conditionD && { d : 5}),
  ...(conditionE && { e : 5}),
 };

console.log(b);

包装成一个对象

像这样的东西比较干净

 const obj = {
   X: 'dataX',
   Y: 'dataY',
   //...
 }

 const list = {
   A: true && 'dataA',
   B: false && 'dataB',
   C: 'A' != 'B' && 'dataC',
   D: 2000 < 100 && 'dataD',
   // E: conditionE && 'dataE',
   // F: conditionF && 'dataF',
   //...
 }

 Object.keys(list).map(prop => list[prop] ? obj[prop] = list[prop] : null)

包装成数组

或者如果你想使用Jamie Hill的方法并且有一个很长的条件列表,那么你必须写。语法多次。为了更简洁,可以将它们包装到一个数组中,然后使用reduce()将它们作为单个对象返回。

const obj = {
  X: 'dataX',
  Y: 'dataY',
  //...

...[
  true && { A: 'dataA'},
  false && { B: 'dataB'},
  'A' != 'B' && { C: 'dataC'},
  2000 < 100 && { D: 'dataD'},
  // conditionE && { E: 'dataE'},
  // conditionF && { F: 'dataF'},
  //...

 ].reduce(( v1, v2 ) => ({ ...v1, ...v2 }))
}

或者使用map()函数

const obj = {
  X: 'dataX',
  Y: 'dataY',
  //...
}

const array = [
  true && { A: 'dataA'},
  false &&  { B: 'dataB'},
  'A' != 'B' && { C: 'dataC'},
  2000 < 100 && { D: 'dataD'},
  // conditionE && { E: 'dataE'},
  // conditionF && { F: 'dataF'},
  //...

 ].map(val => Object.assign(obj, val))

我用另一个选项做了一个小的基准测试。我喜欢从一些物体上去除“累赘”。通常是错误的值。

以下是本尼的结果:

清洁

const clean = o => {
    for (const prop in o) if (!o) delete o[prop];
}

clean({ value });

传播

let a = {
    ...(value && {b: value})
};

if

let a = {};
if (value) {
    a.b = value;
}

结果

clean  :  84 918 483 ops/s, ±1.16%    | 51.58% slower    
spread :  20 188 291 ops/s, ±0.92%    | slowest, 88.49% slower    
if     : 175 368 197 ops/s, ±0.50%    | fastest

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

const a = {
   ...(someCondition && {b: 5})
}