1006

I would like to create an object with a member added conditionally. The simple approach is:

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

Now, I would like to write a more idiomatic code. I am trying:

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

But now, b is a member of a whose value is undefined. This is not the desired result.

Is there a handy solution?

Update

I seek for a solution that could handle the general case with several members.

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),
 };
Audwin Oyong
  • 2,247
  • 3
  • 15
  • 32
viebel
  • 19,372
  • 10
  • 49
  • 83
  • 21
    Not sure there's a such thing as idiomatic JavaScript... – Michael Berkowski Jul 28 '12 at 20:14
  • Does it actually matter? If you never defined `a.b`, retrieving `a.b` would return `undefined` anyway. – Teemu Jul 28 '12 at 20:15
  • 12
    @Teemu: It could matter when the `in` operator is used. –  Jul 28 '12 at 20:17
  • @amnotiam Oops... that's true, seems that I wasn't thinking all aspects... – Teemu Jul 28 '12 at 20:19
  • Well, you've taken a step closer to telling us what you're actually needing. Now perhaps you'll take it the rest of the way, and describe what `conditionB-G` actually represent. Perhaps a loop would be helpful? –  Jul 28 '12 at 20:24
  • `conditionB-G` are independent conditions which are not known a priori. – viebel Jul 28 '12 at 20:25
  • What is an unknown condition? Is it eval'd into the code? –  Jul 28 '12 at 20:27
  • I mean that I look for a general pattern to write the code. This pattern should not depend on the conditions. – viebel Jul 28 '12 at 20:31
  • Yeah, I know. I'm saying the pattern could depend on the type of condition. If you want to know if there's a way to use object literal syntax that excludes some of the literal properties being defined, then no there isn't. Depending on the type of condition, your best bet may just be to put your `if` in a loop. –  Jul 28 '12 at 20:53
  • 5
    There is no way to have conditional properties in literal objects for now, but I wish they add it in ES7, this could be very handy especially in server side programming! – Ali Sep 10 '16 at 22:38
  • If anyone finds this question but was looking for conditional computed properties instead of just conditional properties, head to this question and vote to reopen: https://stackoverflow.com/questions/62214748/how-to-conditionally-add-a-computed-property-name-to-an-object-in-javascript – Christiaan Westerbeek Jun 05 '20 at 12:56

30 Answers30

2109

I think @InspiredJW did it with ES5, and as @trincot pointed out, using es6 is a better approach. But we can add a bit more sugar, by using the spread operator, and logical AND short circuit evaluation:

const a = {
   ...(someCondition && {b: 5})
}
Yan Khonski
  • 12,225
  • 15
  • 76
  • 114
Jamie Hill
  • 21,139
  • 2
  • 13
  • 4
  • 9
    I'm not so sure this is correct, the [proposal](https://github.com/sebmarkbage/ecmascript-rest-spread/blob/master/Spread.md) states `Null/Undefined Are Ignored`, it does not say `false` is ignored. Transpilers may allow this through at present, but is it compliant? The following ought to be `{...someCondition ? {b: 5} : null}` but isn't as compact. – Benjamin Dobell Feb 28 '17 at 15:36
  • Sorry, upon digging further. The behaviour of the spec _does_ allow this syntax - although, not due to any sort of special case handling for false booleans in the same way `null` or `undefined` are handled - just due to some low-level language semantics converting primitives to objects. Anyway, it's just the proposal _summary_ that's a bit confusing - the proposal is fine and allows this syntax. Phew! – Benjamin Dobell Feb 28 '17 at 18:18
  • 60
    I asked if this was valid to the people who made spread proposal and they said this is fine. https://github.com/tc39/proposal-object-rest-spread/issues/45 , cc @BenjaminDobell – 김민준 May 17 '17 at 03:14
  • 141
    @AlanH spread operator is like a shorthand of `Object.assign` and have lower precedence than the && operator. It ignore value without property (boolean, null, undefined, number), and add all properties of the object after the `...` in place. remember the `&&` operator return the right value if true, or false otherwise. so if `someCondition` is true, `{b : 5}` will be passed to the `...` operator, resulting in adding the property `b` to `a` with value `5`. is `someCondition` is false, `false`will be passed to the `...` operator. resulting in nothing added. it's clever. I love it. – Félix Brunet Jul 13 '17 at 16:12
  • 19
    Great answer, but putting the condition and the resulting object being spread into parentheses will greatly improve readability of this example. Not everyone remembers JS operator precedence by heart. – Neurotransmitter Aug 25 '17 at 07:51
  • @TranslucentCloud what do you mean? can you write an example of that syntax? and if you can, please explain why it is more readable in your opinion. i'm curious :) – Sagiv b.g Jan 25 '18 at 13:17
  • 1
    I mean: `...(someCondition && {b: 5})`. – Neurotransmitter Jan 26 '18 at 13:42
  • @TranslucentCloud Aw, i thought you were talking about something else. but yeah, wrapping it in parens does make it a bit more readable. it reminds me of [this article](http://2ality.com/2017/04/conditional-literal-entries.html) – Sagiv b.g Feb 13 '18 at 23:02
  • This is good. But for chains, there is an issue, you can use hoek.reach to fix it though.`const hoek = require("hoek");` `let foo = { a: { b: { c:"foo string", d:false, e:true } } };` `let retval1 = {` `...(hoek.reach(foo, 'a.b.c') && {thing1: foo.a.b.c}),` `...(hoek.reach(foo, 'a.b.d') && {thing3: foo.a.b.d}),//Not OK for false` `...(hoek.reach(foo, 'a.b.e') && {thing2: foo.a.b.e}),` `...(hoek.reach(foo, 'a.z.e') && {thing2: foo.a.z.e})//OK for non-existance` `};` – ggb667 Apr 19 '18 at 13:26
  • 13
    The only other issue is you can't use this for false booleans. – ggb667 Apr 19 '18 at 13:31
  • 6
    @ggb667 yes you can, with double negation `...(!!someFalsyCondition && {b: 5})` – Cyril CHAPON May 09 '18 at 08:54
  • 3
    Be careful, this doesn't work with arrays too. Spread operator throws when spreading null on arrays. https://github.com/tc39/ecma262/issues/687 – Cyril CHAPON Jul 10 '18 at 14:01
  • 1
    This doesn't work for me. If `someCondition` is `undefined`, I get an `Uncaught ReferencError`. I'm verifying this in Chrome's console. – Michael P. Aug 31 '18 at 18:07
  • 1
    as @CyrilCHAPON pointed out, it does not work for arrays - gave my some head scratches. Instead do this: `const a = [...(maybeArray || [])]` – ford04 May 17 '19 at 14:21
  • Quick question, sometimes this syntax does not work on browser consoles. I've tried on chrome, it works but my co-worker's chrome it doesn't work. On Microsoft Edge, it doesn't work. Should I be worried? – inertia Jul 03 '19 at 15:58
  • @jake you should worry only if you don't compile your javascript before deployment with tools like babels and don't implements the polyfills for the ES6 feature you are using in your code, but you should worry about any ES6 feature if that's the case, not this in particular. – Yuri Scarbaci Oct 04 '19 at 09:21
  • If you go to chrome console now and you try running this solution without defining `someCondition` you will get an error. – Enmanuel Duran May 13 '20 at 18:55
  • This is the best answer. Just want to also mention that you can omit the parens. `{...true && {a: 'a'}}` – TravRob Jan 08 '21 at 17:03
  • 1
    It’s better to make the intent more explicit with `({ ...(someCondition ? { b: 5 } : {}) })`; e.g. this won’t work if `someCondition === document.all`, or with other falsy values which have own properties (which the specification doesn’t prohibit). – Sebastian Simon Mar 14 '21 at 04:53
  • @inertia Make sure you force the object literal to be in expression context. `{}` is a block if not in expression context, so typing `{ ...(someCondition && { b: 5 }) }` in the console won’t work for some browsers, unless you wrap the object literal in parentheses. See [Why does `{} == null` give a SyntaxError?](https://stackoverflow.com/q/53306680/4642212). – Sebastian Simon Mar 14 '21 at 04:55
  • It is not safe, '...' only available for objec,so you will get error like: ```Spread types may only be created from object types.ts(2698) ``` if 'someCondition' return falsy. – leonardosccd Jan 06 '23 at 08:24
  • https://github.com/tc39/proposal-object-rest-spread/issues/45 , The comment which justifies the above solution, have mentioned `Object.assign will treat all primitives as same` in that case , it treats `string` by splitting the characters. Which is kind of confusing as string comes under primitive { ...{ true & 'abc'}} = { '0': a , '1': b, '2': c} – Amerrnath Jan 16 '23 at 06:40
  • for typescript users: ...(someCondition && {b: 5})as any – Hassan Kandil Jan 18 '23 at 13:16
327
const obj = {
   ...(condition) && {someprop: propvalue},
   ...otherprops
}

Live Demo:

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

console.log(obj);
Seph Reed
  • 8,797
  • 11
  • 60
  • 125
Lagistos
  • 3,539
  • 1
  • 10
  • 18
  • 22
    While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Ralf Stubner Jul 05 '18 at 22:23
  • 11
    What does this answer add to [Jamie Hill's answer from 2 years earlier](https://stackoverflow.com/questions/11704267/in-javascript-how-to-conditionally-add-a-member-to-an-object/40560953#40560953)? – Dan Dascalescu Jan 21 '19 at 10:19
  • if cond does not match than this will return undefined. – Mustkeem K Feb 06 '19 at 13:23
  • No, if the condition is false nothing will be added. The spread syntax will get an object of the some prop and destruct it if the condition is true or false and then it will add nothing – Lagistos Feb 09 '19 at 08:00
  • This is not a valid syntax. Spread can only be used with iterables. https://stackoverflow.com/questions/52903050/babel-7-and-webpack-4-not-working-for-conditional-spread-operation-in-arrayshor/55396142#55396142 – Itai Noam Mar 28 '19 at 11:15
  • It's valid and you can try it – Lagistos Mar 29 '19 at 12:03
  • 4
    Short explanation goes like this: "..." spread operator deconstructs the object literal and adds it to "obj" e.g. in this case ...(true) && {someprop: 42}, the whole term that is to be deconstructed is "(true) && {someprop: 42}", in this case the boolean is true and the term just yields {someprop:42} which is then deconstructed and added into obj. if the boolean is false instead, then the term will just be false, and nothing will be deconstructed and added into obj – Qiong Wu Sep 26 '19 at 10:25
  • I am getting `Type '{ ... }' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488)` – Sigex May 01 '21 at 16:35
  • _Prettier_ auto-formats it to `...(true && {someprop: 42}),` – ADTC Oct 18 '22 at 02:46
154

I suggest the following:

const a = {
   ...(someCondition? {b: 5}: {})
}
Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Itai Noam
  • 3,815
  • 3
  • 18
  • 14
  • 2
    This answer is awesome! Made a gist with an example of conditionally adding authorization field to fetch params for POST here: https://gist.github.com/mattlockyer/3dac7c9618ac98d16b046e32c364899d – mattdlockyer Jun 19 '19 at 15:25
  • This is indeed more readable than the shorter `someCondition && {b:5}` – Vincent J Nov 09 '22 at 10:45
138

In pure Javascript, I cannot think of anything more idiomatic than your first code snippet.

If, however, using the jQuery library is not out of the question, then $.extend() should meet your requirements because, as the documentation says:

Undefined properties are not copied.

Therefore, you can write:

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

And obtain the results you expect (if conditionB is false, then b will not exist in a).

Kaii
  • 20,122
  • 3
  • 38
  • 60
Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
  • does null work the same way ? or does it have to be undefined ? – Aous1000 Jun 09 '18 at 00:32
  • 9
    This is actually a wrong answer, because it uses jQuery and this ternary condition won't remove a property from an object, this just would set a property as undefined. See @lagistos answer for the correct way to do this, – Alexander Kim Mar 13 '20 at 04:55
121

With EcmaScript2015 you can use 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);

Some remarks:

  • Object.assign modifies the first argument in-place, but it also returns the updated object: so you can use this method in a bigger expression that further manipulates the object.
  • Instead of null you could pass undefined or {}, with the same result. You could even provide 0 instead, because primitive values are wrapped, and Number has no own enumerable properties.

Even more concise

Taking the second point further, you could shorten it as follows (as @Jamie has pointed out), as falsy values have no own enumerable properties (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);
trincot
  • 317,000
  • 35
  • 244
  • 286
111

Conditionally Add a member to an Object

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

// { student: 10 }
Sanjib Debnath
  • 3,556
  • 2
  • 22
  • 16
63

Perfomance test

Classic approach

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

VS

spread operator approach

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

Results:

The classic approach is much faster, so take in consideration that the syntax sugaring is slower.

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
F. Müller
  • 3,969
  • 8
  • 38
  • 49
47

more simplified,

const a = {
    ...(condition && {b: 1}) // if condition is true 'b' will be added.
}
borisdiakur
  • 10,387
  • 7
  • 68
  • 100
Faheel Khan
  • 556
  • 4
  • 4
  • 16
    More simplified? Than the answer that was given 4 years before yours? I don't see what you simplified... – trincot Sep 25 '20 at 14:47
44

SIMPLE ES6 SOLUTION

Single condition with (&) - if condition

const didIPassExam = true

const study = {
  monday : 'writing',
  tuesday : 'reading',
  
  /* check conditionally and if true, then add wednesday to study */

  ...(didIPassExam && {wednesday : 'sleep happily'})
}


console.log(study)

Dual condition with (? :) - if-else condition

const score = 110
//const score = 10

const storage = {
  a:10,
  b:20,
  ...(score > 100  ? {c: 30} : {d:40}) 
}

console.log(storage)

Explanation

Let's say you have storage object like this

const storage = {
  a : 10,
  b : 20,
}

and you would like to add a prop to this conditionally based on score

const score = 90

You would now like to add prop c:30 to storage if score is greater than 100.

If score is less than 100, then you want to add d:40 to storage. You can do like this

const score = 110

const storage = {
  a:10,
  b:20,
  ...(score > 100  ? {c: 30} : {d:40}) 
}

The above code gives storage as

{
  a: 10,
  b: 20,
  c: 30
}

If score = 90

then you get storage as

{
  a: 10,
  b: 20,
  d: 40
}

Codepen example

Sandeep Amarnath
  • 5,463
  • 3
  • 33
  • 43
  • 1
    Here is the [link](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#spread_in_object_literals) to the MDN docs on this syntax (spread syntax) – code.monger Apr 26 '23 at 23:30
32

What about using Enhanced Object Properties and only set the property if it is truthy, e.g.:

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

So if the condition is not met it doesn't create the preferred property and thus you can discard it. See: http://es6-features.org/#ComputedPropertyNames

UPDATE: It is even better to follow the approach of Axel Rauschmayer in his blog article about conditionally adding entries inside object literals and arrays (http://2ality.com/2017/04/conditional-literal-entries.html):

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

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

Quite helped me a lot.

14

This is probably the shortest solution with ES6

console.log({
   ...true && {foo: 'bar'}
})
// Output: {foo:'bar'}
console.log({
   ...false && {foo: 'bar'}
})
// Output: {}
mateos
  • 1,405
  • 1
  • 17
  • 26
11

I made a small benchmark with one other option. I like to remove "dead weight" from some objects. Usually falsy values.

Here are the benny results:

clean

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

clean({ value });

spread

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

if

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

results

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
icetbr
  • 153
  • 1
  • 2
  • 8
10

I would do this

var a = someCondition ? { b: 5 } : {};
Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
jwchang
  • 10,584
  • 15
  • 58
  • 89
  • @amnotiam I actually would use coffeescript and just do ```a = if someCondition then b:5 else {}``` – jwchang Jul 28 '12 at 20:18
  • 1
    Much better, thank you. Now the only problem is duplication if there are mandatory arguments (`var o = cond ? {a: 1} : {a: 1, b: 2}`). –  Jul 28 '12 at 20:23
  • @InspiredJW: see the update in the question. I want to handle the general case. – viebel Jul 28 '12 at 20:24
7

If the goal is to have the object appear self-contained and be within one set of braces, you could try this:

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

    if (conditionC)
        this.c = 5;

    if (conditionD)
        this.d = 5;
};
Casey Chu
  • 25,069
  • 10
  • 40
  • 59
7

You can add all your undefined values with no condition and then use JSON.stringify to remove them all :

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

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

// Contents of cleaned:

// cleaned = {
//   age: 22,
//   height: null
// }
ProGrammer
  • 976
  • 2
  • 10
  • 27
Milad
  • 27,506
  • 11
  • 76
  • 85
  • This is considered quite slow which might be a factor for big objects but more importantly, it will not only remove undefined values but also any functions defined in your object. – Mikey Sep 24 '22 at 11:38
5

This has long been answered, but looking at other ideas I came up with some interesting derivative:

Assign undefined values to the same property and delete it afterwards

Create your object using an anonymous constructor and always assign undefined members to the same dummy member which you remove at the very end. This will give you a single line (not too complex I hope) per member + 1 additional line at the end.

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;
};
Robert Koritnik
  • 103,639
  • 52
  • 277
  • 404
5

Below code snippet should work.

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);
  • 1
    How is this different than the other answers using the same method? – callback Jul 11 '22 at 13:58
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Ethan Jul 11 '22 at 23:55
  • @callback actually this answers a question that i couldn't find the answer for in the other answers, i was wondering if you could do it multiple times. – deweydb Mar 28 '23 at 21:39
4

If you wish to do this server side (without jquery), you can use lodash 4.3.0:

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

And this works using lodash 3.10.1

a = _.pick({ b: (someCondition? 5 : undefined) }, _.negate(_.isUndefined));
Mickl
  • 88
  • 1
  • 4
3
var a = {
    ...(condition ? {b: 1} : '') // if condition is true 'b' will be added.
}

I hope this is the much efficient way to add an entry based on the condition. For more info on how to conditionally add entries inside an object literals.

Madhankumar
  • 390
  • 4
  • 12
  • 4
    `[...condition?'':['item']]` this will add string item into array – 牛さん Apr 25 '18 at 07:20
  • 2
    How is this answer any better than [Jamie Hill's answer from a year earlier](https://stackoverflow.com/questions/11704267/in-javascript-how-to-conditionally-add-a-member-to-an-object/40560953#40560953)? – Dan Dascalescu Jan 21 '19 at 10:20
  • 1
    @DanDascalescu Jamie Hill's answer is better than my answer, I didn't think in that way and I used to be more of a ternary-operator guy. – Madhankumar Jan 21 '19 at 10:49
2
const isAdult = true;

const obj = {
  ...(isAdult ? { age: 18 }: { age: 17}),
};

//>> { student: 18 }
Gimnath
  • 824
  • 9
  • 11
1

Using lodash library, you can use _.omitBy

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

This results handy when you have requests that are optional

var a = _.omitBy({
    b: req.body.optionalA,  //if undefined, will be removed
    c: req.body.optionalB,
}, _.IsUndefined)
htafoya
  • 18,261
  • 11
  • 80
  • 104
1

This is the most succinct solution I can come up with:

var a = {};
conditionB && a.b = 5;
conditionC && a.c = 5;
conditionD && a.d = 5;
// ...
Đinh Carabus
  • 3,403
  • 4
  • 22
  • 44
1

i prefere, using code this it, you can run this code

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);
fandu139
  • 19
  • 3
1

To expand on the ES6 based answers, I created this utility Typescript functions, that make the usage (in my opinion) more readable and less like a magical formula, and the intention very clear, and has the correct types:

/**
 * Creates a simple object with ot without the specified property and value, depending on the condition.
 * Usage: When creating an object literal that needs to include a property only in some cases.
 * Use it with the spread operator.
 * @example
 * const user = {
 *   username,
 *   // will include the property only if isInternalUser() returns true
 *   ...conditionalObjectProperty('password', isInternalUser(), () => getUserPassword())
 * }
 * @param propertyName
 * @param condition
 * @param valueCreator
 */
export function conditionalObjectProperty<P extends string, V> (propertyName: P, condition: boolean, valueCreator: () => V) {
  return condition
    ? { [propertyName]: valueCreator() }
    : {};
}

/**
 * Specialized conditional property creator that creates an object containing a specified property
 * only when its value is non-nullable.
 * Use in object literals with the spread operator.
 * @example
 * const middleName: string|undefined = getMiddleName();
 * const user = {
 *   userName,
 *   firstName,
 *   lastName,
 *   // will be included only if middleName is non-nullable
 *   ...optionalObjectProperty('middleName', middleName)
 * }
 * @param propertyName
 * @param value
 */
export function optionalObjectProperty<P extends string, V> (propertyName: P, value: V) {
  return conditionalObjectProperty(propertyName, value != null, () => value);
}

Pierre Henry
  • 16,658
  • 22
  • 85
  • 105
0

I think your first approach to adding members conditionally is perfectly fine. I don't really agree with not wanting to have a member b of a with a value of undefined. It's simple enough to add an undefined check with usage of a for loop with the in operator. But anyways, you could easily write a function to filter out undefined members.

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

You could also use the delete operator to edit the object in place.

Yunchi
  • 5,529
  • 2
  • 17
  • 18
0

I hope this helps to solve your problem

<body>
  
    <h1>GeeksforGeeks</h1>
      
    <p id="geeks"></p>
  
      
    <!-- Script to check array include
        object or not -->
    <script>
        var obj = {"geeks1":10, "geeks2":12}
        var arr = ["geeks1", "geeks2", "geeks3", obj];
          
        if(arr.filter(value=> value==obj).length > 0)
            document.write("true");
        else
            document.write("false");
    </script>
</body>
-1

Using lodash library, you can use _.merge

var a = _.merge({}, {
    b: conditionB ? 4 : undefined,
    c: conditionC ? 5 : undefined,
})
  1. If conditionB is false & conditionC is true, then a = { c: 5 }
  2. If both conditionB & conditionC are true, then a = { b: 4, c: 5 }
  3. If both conditionB & conditionC are false, then a = {}
user3437231
  • 262
  • 4
  • 5
  • 1
    I get a different result. I'm using `lodash@^4.0.0`. `undefined` are being included in my case. – JohnnyQ Apr 04 '18 at 00:06
  • @JohnnyQ As of [Lodash version 4.17.21](https://codepen.io/travist/full/jrBjBz/), `_.merge({}, { x: undefined, y: 1 });` returns `{ "y": 1 }`. – Sebastian Simon Mar 14 '21 at 05:09
-1

Wrap into an object

Something like this is a bit cleaner

 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)

Wrap into an array

Or if you want to use Jamie Hill's method and have a very long list of conditions then you must write ... syntax multiple times. To make it a bit cleaner, you can just wrap them into an array, then use reduce() to return them as a single object.

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

Or using map() function

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))
-2

Define a var by let and just assign new property

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",
      },
    ];
}

Now the msg become

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

In my opinion this is very simple and easy solution.

Sohel Ahmed Mesaniya
  • 3,344
  • 1
  • 23
  • 29
-2

For the sake of completeness you can use Object.defineProperty() if you want to add additional descriptors. Note I purposely added enumerable: true otherwise the property wouldn't appear in the console.log(). The advantage with this approach is that you can also use Object.defineProperties() if you want to add multiple new properties (However, in this way every property will be dependent on the same condition...)

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>
Behemoth
  • 5,389
  • 4
  • 16
  • 40