我想创建一个有条件添加成员的对象。 简单的方法是:
var a = {};
if (someCondition)
a.b = 5;
现在,我想写一个更惯用的代码。我在尝试:
a = {
b: (someCondition? 5 : undefined)
};
但现在,b
是a
的成员,其值为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),
};
答案 0 :(得分:512)
我认为@InspiredJW是用ES5做的,正如@trincot指出的那样,使用es6是一种更好的方法。但是我们可以通过使用扩展运算符和逻辑AND短路评估来添加更多的糖:
const a = {
...(someCondition && {b: 5})
}
答案 1 :(得分:87)
在纯Javascript中,我想不出比第一个代码段更惯用的东西。
但是,如果使用jQuery库并不是不可能的,那么$.extend()应该符合您的要求,因为正如文档所说:
未复制未定义的属性。
因此,你可以写:
var a = $.extend({}, {
b: conditionB ? 5 : undefined,
c: conditionC ? 5 : undefined,
// and so on...
});
并获得您期望的结果(如果conditionB
为false
,那么b
中将不存在a
)。
答案 2 :(得分:77)
使用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
。您甚至可以提供false
,因为primitive values are wrapped, and Number
has no own enumerable properties。进一步说明,你可以按如下方式缩短它(正如@Jamie指出的那样),因为假值没有自己的可枚举属性(0
,NaN
,null
,undefined
,''
,Object.assign(a, conditionB && { b: 1 },
conditionC && { c: 2 },
conditionD && { d: 3 });
,document.all
除外):
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);
from __future__ import print_function
答案 3 :(得分:34)
更加简化,
const a = {
...(condition && {b: 1}) // if condition is true 'b' will be added.
}
答案 4 :(得分:21)
如何使用增强对象属性并仅在属性真实时设置属性,例如:
[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'} : {})
};
非常帮助了我。
答案 5 :(得分:17)
const obj = {
...(condition) && {someprop: propvalue},
...otherprops
}
答案 6 :(得分:14)
性能测试
经典方法
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
答案 7 :(得分:13)
更好的答案:
const a = {
...(someCondition ? {b: 5} : {})
}
答案 8 :(得分:10)
将扩展语法与布尔值一起使用(如此处所建议)是无效语法。 点差只能使用with iterables。
我建议以下内容:
const a = {
...(someCondition? {b: 5}: {} )
}
答案 9 :(得分:5)
如果目标是使对象看起来是自包含的并且在一组大括号内,您可以尝试这样做:
var a = new function () {
if (conditionB)
this.b = 5;
if (conditionC)
this.c = 5;
if (conditionD)
this.d = 5;
};
答案 10 :(得分:5)
如果你想做这个服务器端(没有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));
答案 11 :(得分:4)
这已经得到了很长时间的回答,但是看看其他想法我想出了一些有趣的衍生物:
使用匿名构造函数创建对象,并始终将未定义的成员分配给您在最后删除的同一 dummy 成员。这将给你一个单行(我希望不是太复杂)每个成员+最后一行额外的行。
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;
};
答案 12 :(得分:4)
var a = {
...(condition ? {b: 1} : '') // if condition is true 'b' will be added.
}
我希望这是根据条件添加条目的高效方法。 有关如何在对象文字中有条件地添加条目的更多信息。
答案 13 :(得分:3)
这可能是ES6中最短的解决方案
console.log({
...true && {foo: 'bar'}
})
// Output: {foo:'bar'}
console.log({
...false && {foo: 'bar'}
})
// Output: {}
答案 14 :(得分:1)
有条件地向对象添加成员
const trueCondition = true;
const falseCondition = false;
const obj = {
...(trueCondition && { student: 10 }),
...(falseCondition && { teacher: 2 }),
};
// { student: 10 }
答案 15 :(得分:1)
我会这样做
var a = someCondition ? { b: 5 } : {};
使用一个行代码版本
进行编辑答案 16 :(得分:1)
您可以无条件添加所有未定义的值,然后使用JSON.stringify
将其全部删除:
const person = {
name:undefined,
age:22,
height:null
}
const cleaned = JSON.parse(JSON.stringify(person));
//cleaned = {
// age:22,
// height:null
// }
答案 17 :(得分: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);
答案 18 :(得分:1)
通过let
定义变量,然后分配新属性
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",
},
]
}
我认为这是一个非常简单容易的解决方案。
答案 19 :(得分:0)
为了完整起见,如果您想添加额外的 Online demo,可以使用 Object.defineProperty()
。请注意,我特意添加了 embed = new MessageEmbed().setImage(url)
displayMessage.edit({ embeds: [embed] })
,否则该属性不会出现在 enumerable: true
中。这种方法的优点是,如果您想添加多个新属性,您还可以使用 descriptors(但是,这样每个属性都将依赖于相同的条件...)
console.log()
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);
};
答案 20 :(得分:0)
我认为你有条件地添加成员的第一种方法是完全没问题的。我不同意不希望b
的成员a
的值为undefined
。使用undefined
运算符对for
循环的使用添加in
检查非常简单。但无论如何,您可以轻松编写一个函数来过滤掉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
运算符来编辑对象。
答案 21 :(得分:0)
这是我能提出的最简洁的解决方案:
var a = {};
conditionB && a.b = 5;
conditionC && a.c = 5;
conditionD && a.d = 5;
// ...
答案 22 :(得分:0)
包装到对象
像这样的东西更干净
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))
答案 23 :(得分:0)
使用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)
答案 24 :(得分:-1)
使用lodash库,您可以使用 _。合并
select p1.pid, p1.name, p2.name
from p p1
join p p2
on p1.pid = p2.pid
and p1.name < p2.name
order by p1.pid, p1.name, p2.name
var a = _.merge({}, {
b: conditionB ? 4 : undefined,
c: conditionC ? 5 : undefined,
})
&amp; conditionC是false
,然后是true
a = { c: 5 }
,然后是true
a = { b: 4, c: 5 }
,然后是false