712

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

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

24 回答 24

1560

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

const a = {
   ...(someCondition && {b: 5})
}
于 2016-11-12T08:22:24.297 回答
209
const obj = {
   ...(condition) && {someprop: propvalue},
   ...otherprops
}

现场演示:

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

console.log(obj);

于 2018-07-05T22:00:21.353 回答
138

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

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

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

因此,您可以编写:

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

并获得你期望的结果(如果conditionBfalse,那么b将不存在于a)。

于 2012-07-28T20:45:40.753 回答
114

我建议如下:

const a = {
   ...(someCondition? {b: 5}: {})
}
于 2019-03-28T11:24:16.370 回答
113

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

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

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

console.log(a);

一些备注:

更简洁

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

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

var a, conditionB, conditionC, conditionD;
conditionC = "this is truthy";
conditionD = NaN; // falsy
a = {};
Object.assign(a, conditionB && { b: 1 },
                 conditionC && { c: 2 },
                 conditionD && { d: 3 });
console.log(a);

于 2016-07-20T14:10:35.617 回答
63

有条件地向对象添加成员

const trueCondition = true;
const falseCondition = false;
const obj = {
  ...(trueCondition && { student: 10 }),
  ...(falseCondition && { teacher: 2 }),
};

// { student: 10 }
于 2021-06-06T19:32:54.573 回答
46

性能测试

经典方法

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

VS

传播算子方法

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

结果

经典方法要快得多,因此请考虑到语法糖化较慢。

testClassicConditionFulfilled(); // ~ 234.9ms
testClassicConditionNotFulfilled(); // ~493.1ms
testSpreadOperatorConditionFulfilled(); // ~2649.4ms
testSpreadOperatorConditionNotFulfilled(); // ~2278.0ms

function testSpreadOperatorConditionFulfilled() {
  const value = 5;

  console.time('testSpreadOperatorConditionFulfilled');
  for (let i = 0; i < 200000000; i++) {
    let a = {
      ...(value && {b: value})
    };
  }
  console.timeEnd('testSpreadOperatorConditionFulfilled');
}

function testSpreadOperatorConditionNotFulfilled() {
  const value = undefined;

  console.time('testSpreadOperatorConditionNotFulfilled');
  for (let i = 0; i < 200000000; i++) {
    let a = {
      ...(value && {b: value})
    };
  }
  console.timeEnd('testSpreadOperatorConditionNotFulfilled');
}

function testClassicConditionFulfilled() {
  const value = 5;

  console.time('testClassicConditionFulfilled');
  for (let i = 0; i < 200000000; i++) {
    let a = {};
    if (value)
        a.b = value;
  }
  console.timeEnd('testClassicConditionFulfilled');
}

function testClassicConditionNotFulfilled() {
  const value = undefined;

  console.time('testClassicConditionNotFulfilled');
  for (let i = 0; i < 200000000; i++) {
    let a = {};
    if (value)
        a.b = value;
  }
  console.timeEnd('testClassicConditionNotFulfilled');
}

testClassicConditionFulfilled(); // ~ 234.9ms
testClassicConditionNotFulfilled(); // ~493.1ms
testSpreadOperatorConditionFulfilled(); // ~2649.4ms
testSpreadOperatorConditionNotFulfilled(); // ~2278.0ms

于 2020-07-15T12:03:20.403 回答
44

更简化,

const a = {
    ...(condition && {b: 1}) // if condition is true 'b' will be added.
}
于 2020-04-01T08:34:26.317 回答
30

使用增强的对象属性怎么样,并且只在它是真实的情况下设置属性,例如:

[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'} : {})
};

对我帮助很大。

于 2017-11-16T13:48:36.910 回答
11

这可能是 ES6 中最短的解决方案

console.log({
   ...true && {foo: 'bar'}
})
// Output: {foo:'bar'}
console.log({
   ...false && {foo: 'bar'}
})
// Output: {}
于 2020-10-04T14:32:42.413 回答
9

我会这样做

var a = someCondition ? { b: 5 } : {};
于 2012-07-28T20:10:40.423 回答
8

您可以无条件添加所有未定义的值,然后使用JSON.stringify将它们全部删除:

const person = {
  name: undefined,
  age: 22,
  height: null
}

const cleaned = JSON.parse(JSON.stringify(person));

// Contents of cleaned:

// cleaned = {
//   age: 22,
//   height: null
// }
于 2018-07-15T09:06:58.100 回答
7

如果目标是让对象看起来是独立的并且在一组大括号内,你可以试试这个:

var a = new function () {
    if (conditionB)
        this.b = 5;

    if (conditionC)
        this.c = 5;

    if (conditionD)
        this.d = 5;
};
于 2012-07-28T20:57:38.850 回答
5

这早就得到了回答,但是看着其他想法,我想出了一些有趣的衍生物:

为同一属性分配未定义的值,然后将其删除

使用匿名构造函数创建您的对象,并始终将未定义的成员分配给您在最后删除的同一个虚拟成员。这将为每个成员提供一行(我希望不是太复杂)+ 1 个附加行。

var a = new function() {
    this.AlwaysPresent = 1;
    this[conditionA ? "a" : "undef"] = valueA;
    this[conditionB ? "b" : "undef"] = valueB;
    this[conditionC ? "c" : "undef"] = valueC;
    this[conditionD ? "d" : "undef"] = valueD;
    ...
    delete this.undef;
};
于 2014-12-10T01:54:55.853 回答
4

如果你希望做这个服务器端(没有 jquery),你可以使用 lodash 4.3.0:

a = _.pickBy({ b: (someCondition? 5 : undefined) }, _.negate(_.isUndefined));

这可以使用 lodash 3.10.1

a = _.pick({ b: (someCondition? 5 : undefined) }, _.negate(_.isUndefined));
于 2016-02-11T01:29:48.373 回答
2
var a = {
    ...(condition ? {b: 1} : '') // if condition is true 'b' will be added.
}

我希望这是根据条件添加条目的有效方法。有关如何有条件地在对象文字中添加条目的更多信息。

于 2017-12-29T10:19:45.897 回答
1

使用 lodash 库,您可以使用_.omitBy

var a = _.omitBy({
    b: conditionB ? 4 : undefined,
    c: conditionC ? 5 : undefined,
}, _.IsUndefined)

当您有可选的请求时,这很方便

var a = _.omitBy({
    b: req.body.optionalA,  //if undefined, will be removed
    c: req.body.optionalB,
}, _.IsUndefined)
于 2018-05-18T22:59:06.383 回答
1

这是我能想到的最简洁的解决方案:

var a = {};
conditionB && a.b = 5;
conditionC && a.c = 5;
conditionD && a.d = 5;
// ...
于 2019-09-15T18:29:20.757 回答
1

我更喜欢,使用它的代码,你可以运行这个代码

const three = {
  three: 3
}

// you can active this code, if you use object `three is null`
//const three = {}

const number = {
  one: 1,
  two: 2,
  ...(!!three && three),
  four: 4
}

console.log(number);
于 2020-07-28T01:17:26.383 回答
0

我认为您第一种有条件地添加成员的方法非常好。我真的不同意不想拥有一个b值为. 使用操作员使用循环添加检查非常简单。但无论如何,您可以轻松编写一个函数来过滤掉成员。aundefinedundefinedforinundefined

var filterUndefined = function(obj) {
  var ret = {};
  for (var key in obj) {
    var value = obj[key];
    if (obj.hasOwnProperty(key) && value !== undefined) {
      ret[key] = value;
    }
  }
  return ret;
};

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

您还可以使用delete操作符在原地编辑对象。

于 2012-07-28T20:50:24.190 回答
-1

使用 lodash 库,您可以使用_.merge

var a = _.merge({}, {
    b: conditionB ? 4 : undefined,
    c: conditionC ? 5 : undefined,
})
  1. 如果条件 B 是false& 条件 C 是true,那么a = { c: 5 }
  2. 如果条件 B 和条件 C 都是true,则a = { b: 4, c: 5 }
  3. 如果条件 B 和条件 C 都是false,则a = {}
于 2018-03-26T19:15:39.457 回答
-1

包装成一个对象

像这样的东西有点干净

 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))
于 2019-05-06T12:38:22.757 回答
-1

定义一个 varlet并分配新属性

let msg = {
    to: "hito@email.com",
    from: "hifrom@email.com",
    subject: "Contact form",    
};

if (file_uploaded_in_form) { // the condition goes here
    msg.attachments = [ // here 'attachments' is the new property added to msg Javascript object
      {
        content: "attachment",
        filename: "filename",
        type: "mime_type",
        disposition: "attachment",
      },
    ];
}

现在msg成为

{
    to: "hito@email.com",
    from: "hifrom@email.com",
    subject: "Contact form",
    attachments: [
      {
        content: "attachment",
        filename: "filename",
        type: "mime_type",
        disposition: "attachment",
      },
    ]
}

在我看来,这是非常简单易行的解决方案。

于 2020-06-16T15:14:29.333 回答
-2

为了完整起见,Object.defineProperty()如果您想添加额外的描述符,您可以使用。请注意,我特意添加enumerable: true了该属性,否则该属性将不会出现在console.log(). 这种方法的优点是,Object.defineProperties()如果您想添加多个新属性,也可以使用(但是,这样每个属性都将依赖于相同的条件......)

const select = document.getElementById("condition");
const output = document.getElementById("output");
let a = {};
let b = {};

select.onchange = (e) => {
  const condition = e.target.value === "true";
  condition
    ? Object.defineProperty(a, "b", {
        value: 5,
        enumerable: true,
      })
    : (a = {});

  condition
    ? Object.defineProperties(b, {
        c: {
          value: 5,
          enumerable: true,
        },
        d: {
          value: 6,
          enumerable: true,
        },
        e: {
          value: 7,
          enumerable: true,
        },
      })
    : (b = {});

  outputSingle.innerText = JSON.stringify(a);
  outputMultiple.innerText = JSON.stringify(b);
};
Condition:
<select id="condition">
  <option value="false">false</option>
  <option value="true">true</option>
</select>
<br/>
<br/>
Single Property: <pre id="outputSingle">{}</pre><br/>
Multiple Properties: <pre id="outputMultiple">{}</pre>

于 2021-08-07T19:08:32.533 回答