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

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

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),};
480866 次浏览

我会这么做的

var a = someCondition ? { b: 5 } : {};

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

但是,如果使用jQuery库不是不可能的,那么$//扩展名应该满足您的要求,因为正如留档所说:

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

因此,你可以写:

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

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

我认为你有条件添加成员的第一种方法非常好。我真的不同意不想让ab成员值为undefined。使用in运算符的for循环添加undefined检查很简单。但无论如何,你可以轻松编写一个函数来过滤掉undefined成员。

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运算符在适当的位置编辑对象。

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

var a = new function () {if (conditionB)this.b = 5;
if (conditionC)this.c = 5;
if (conditionD)this.d = 5;};

这个问题早就有了答案,但是看看其他的想法,我想出了一些有趣的衍生工具:

将未定义的值分配给相同的属性并在之后将其删除

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

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

如果你想做这个服务器端(没有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));

使用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);

备注:

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

更简洁

进一步考虑第二点,您可以将其缩短如下(正如@Jamie所指出的),因为false sy值没有自己的可枚举属性(false0NaNnullundefined'',除了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; // falsya = {};Object.assign(a, conditionB && { b: 1 },conditionC && { c: 2 },conditionD && { d: 3 });console.log(a);

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

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

如何使用增强的对象属性并仅在属性为true时设置属性,例如:

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

帮了我很多。

var a = {...(condition ? {b: 1} : '') // if condition is true 'b' will be added.}

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

使用Lodash库,您可以使用_合并

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 = {}

使用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 removedc: req.body.optionalB,}, _.IsUndefined)
const obj = {...(condition) && {someprop: propvalue},...otherprops}

现场演示:

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

您可以添加所有未定义的值,没有条件,然后使用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// }

我建议如下:

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

包裹在一个物体中

像这样的东西稍微干净一点

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

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

var a = {};conditionB && a.b = 5;conditionC && a.c = 5;conditionD && a.d = 5;// ...

更简化,

const a = {...(condition && {b: 1}) // if condition is true 'b' will be added.}

通过let定义一个var并分配新属性

let msg = {to: "hito@email.com",from: "hifrom@email.com",subject: "Contact form",};
if (file_uploaded_in_form) { // the condition goes heremsg.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",},]}

在我看来,这是一个非常简单和容易的解决方案。

性能测试

经典方法

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

VS

点差算子方法

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

结果

经典的方法要快得多,所以要考虑到语法加糖速度较慢。

测试经典条件满足(); // ~ 234.9 ms
测试经典条件未完成(); // ~493.1 ms
测试扩展运算符条件满足(); // ~2649.4 ms
测试扩展运算符条件未完成(); // ~2278.0 ms

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.9mstestClassicConditionNotFulfilled(); // ~493.1mstestSpreadOperatorConditionFulfilled(); // ~2649.4mstestSpreadOperatorConditionNotFulfilled(); // ~2278.0ms

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

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

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

console.log({...true && {foo: 'bar'}})// Output: {foo:'bar'}
console.log({...false && {foo: 'bar'}})// Output: {}

有条件地将成员添加到对象

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

为了完整起见,如果你想添加额外的描述符,你可以使用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>

我用另一个选项做了一个小基准。我喜欢从一些对象中删除“自重”。通常是假值。

以下是benny结果:

干净

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

传播

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

如果

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

结果

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

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

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

我希望这有助于解决你的问题

<body>  
<h1>GeeksforGeeks</h1>      
<p id="geeks"></p>  
      
<!-- Script to check array includeobject 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");elsedocument.write("false");</script></body>

简单的ES6解决方案

带有(&)的单一条件

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)

对偶条件(?:)

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

补充说明

假设你有像这样的storage对象

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

你想根据score有条件地添加一个道具

const score = 90

如果score大于100,您现在想将propc:30添加到storage

如果分数小于100,则要将d:40添加到storage。您可以这样做

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

上面的代码给出了storage作为

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

如果score = 90

然后你得到storage作为

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

代码描述示例

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