在 JavaScript 中,如何有条件地向对象添加成员
In JavaScript, how to conditionally add a member to an object?
我想创建一个有条件地添加成员的对象。简单的方法是:
var a = {};
if (someCondition)
a.b = 5;
现在,我想写一个更惯用的代码。我正在尝试:
a = {
b: (someCondition? 5 : undefined)
};
但是现在,b
是价值undefined
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),
};
@InspiredJW用 ES5 做到了,正如@trincot指出的那样,使用 es6 是一种更好的方法。 但是我们可以通过使用点差运算符和逻辑 AND 短路评估来添加更多的糖:
const a = {
...(someCondition && {b: 5})
}
const obj = {
...(condition) && {someprop: propvalue},
...otherprops
}
现场演示:
const obj = {
...(true) && {someprop: 42},
...(false) && {nonprop: "foo"},
...({}) && {tricky: "hello"},
}
console.log(obj);
我建议如下:
const a = {
...(someCondition? {b: 5}: {})
}
在纯Javascript中,我想不出比你的第一个代码片段更惯用的东西了。
但是,如果使用 jQuery 库并非不可能,那么 $.extend(( 应该可以满足您的要求,因为正如文档所述:
不会复制未定义的属性。
因此,您可以编写:
var a = $.extend({}, {
b: conditionB ? 5 : undefined,
c: conditionC ? 5 : undefined,
// and so on...
});
并获得您期望的结果(如果conditionB
false
,则b
在a
中将不存在(。
使用 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
,因为基元值是包装的,并且Number
没有自己的可枚举属性。
更简洁
更进一步,你可以将其缩短如下(正如@Jamie所指出的(,因为 falsy 值没有自己的可枚举属性(false
、0
、NaN
、null
、undefined
、''
,除了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);
有条件地向对象添加成员
const trueCondition = true;
const falseCondition = false;
const obj = {
...(trueCondition && { student: 10 }),
...(falseCondition && { teacher: 2 }),
};
// { student: 10 }
性能测试
经典方法
const a = {};
if (someCondition)
a.b = 5;
与
点差运算符方法
const a2 = {
...(someCondition && {b: 5})
}
结果:
经典方法要快得多,因此请注意语法加糖速度较慢。
testClassicConditionFulfilled((;//~ 234.9ms
testClassicConditionNotFul((;~493.1毫秒
testSpreadOperatorConditionFul((;~2649.4毫秒
testSpreadOperatorConditionNotFul((;~2278.0毫秒
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
更简化,
const a = {
...(condition && {b: 1}) // if condition is true 'b' will be added.
}
简单的 ES6 解决方案
具有 (&( - 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)
双重条件与 (? :) - if-else condition
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
您现在想将道具c:30
添加到storage
如果score
大于 100
.
如果分数小于 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
}
代码笔示例
使用增强的对象属性并仅在真实时才设置属性怎么样,例如:
[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'} : {})
};
对我帮助很大。
这可能是 ES6 最短的解决方案
console.log({
...true && {foo: 'bar'}
})
// Output: {foo:'bar'}
console.log({
...false && {foo: 'bar'}
})
// Output: {}
我用另一个选项做了一个小的基准测试。我喜欢从某些物体上去除"自重"。通常是虚假值。
以下是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% slower
spread : 20 188 291 ops/s, ±0.92% | slowest, 88.49% slower
if : 175 368 197 ops/s, ±0.50% | fastest
我会这样做
var a = someCondition ? { b: 5 } : {};
如果目标是使对象看起来自包含并在一组大括号内,您可以尝试以下操作:
var a = new function () {
if (conditionB)
this.b = 5;
if (conditionC)
this.c = 5;
if (conditionD)
this.d = 5;
};
您可以添加所有未定义的值,不带任何条件,然后使用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
// }
这个问题早就得到了回答,但看看其他想法,我想出了一些有趣的推导:
将未定义的值分配给同一属性,然后将其删除
使用匿名构造函数创建对象,并始终将未定义的成员分配给最后删除的同一虚拟成员。这将为每个成员提供一行(我希望不会太复杂(+ 最后 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;
};
下面的代码片段应该可以工作。
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);
如果你想做这个服务器端(没有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));
var a = {
...(condition ? {b: 1} : '') // if condition is true 'b' will be added.
}
我希望这是根据条件添加条目的有效方法。有关如何有条件地在对象文本中添加条目的详细信息。
const isAdult = true;
const obj = {
...(isAdult ? { age: 18 }: { age: 17}),
};
//>> { student: 18 }
使用 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)
这是我能想到的最简洁的解决方案:
var a = {};
conditionB && a.b = 5;
conditionC && a.c = 5;
conditionD && a.d = 5;
// ...
我更喜欢,使用代码这个它,你可以运行这个代码
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 的答案,我创建了这个实用程序 Typescript 函数,它使用法(在我看来(更具可读性,不像一个神奇的公式,意图非常明确,并且具有正确的类型:
/**
* 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);
}
您有条件地添加成员的第一种方法非常好。我真的不同意不想让一个a
的成员b
,其值为 undefined
.添加undefined
检查与in
运算符一起使用for
循环非常简单。但无论如何,您可以轻松地编写一个函数来过滤掉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
运算符就地编辑对象。
我希望这有助于解决您的问题
<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>
使用 lodash 库,可以使用 _.merge
var a = _.merge({}, {
b: conditionB ? 4 : undefined,
c: conditionC ? 5 : undefined,
})
- 如果条件 B
false
且条件 Ctrue
,则a = { c: 5 }
- 如果条件B和条件C都
true
,则a = { b: 4, c: 5 }
- 如果条件B和条件C都
false
,则a = {}
换行到对象中
像这样的东西更干净一些
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))
通过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",
},
]
}
在我看来,这是非常简单易行的解决方案。
为了完整起见,如果要添加其他描述符,可以使用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>
- 如果使用 lodash 将属性存在于另一个对象中,则向对象添加属性
- Meteor-将选定窗体中的对象添加到集合中
- 在play2框架中向json对象添加下拉列表项
- 如何在javascript上向数组的对象添加新元素
- JSON到对象数组,并向每个对象添加项
- 如何将一个对象添加到每个对象数组中
- 向Angular作用域对象添加对象数组——TypeError
- CoffeeScript将对象添加到数组中
- 如何从Addon SDK向选项卡对象添加进度侦听器
- 使用ja将对象添加到HTML画布中
- 向通过ReST JSON调用生成的Angular Javascript对象添加方法
- 将新对象添加到本地存储
- 为什么可以'我们在函数体中为函数对象添加属性,就像在javascript中为对象文字添加属性一样
- 使用游标循环将JS对象添加到数组中
- 向调用全局javascript函数的对象添加处理程序
- 将另一个文件中的对象添加到单独文件中的阵列中
- 将对象添加到数组中
- 为新对象添加函数,将对象添加到数组中.理解困难'这'关键字
- sequelize为找到的对象添加值
- 向对象添加新方法和值,同时避免重复