В Javascript, как условно добавить член к объекту?
Я хотел бы создать объект с добавленным членом.
Простой подход:
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),
};
Ответы
Ответ 1
В чистом Javascript я не могу придумать ничего более идиоматичного, чем ваш первый фрагмент кода.
Если, однако, использование библиотеки jQuery не может быть и речи, то $. extend() должно соответствовать вашим требованиям, потому что, поскольку в документации говорится:
Undefined свойства не копируются.
Поэтому вы можете написать:
var a = $.extend({}, {
b: conditionB ? 5 : undefined,
c: conditionC ? 5 : undefined,
// and so on...
});
И получите ожидаемые результаты (если conditionB
- false
, то b
не будет существовать в a
).
Ответ 2
Я думаю, @InspiredJW сделал это с ES5, и, как отметил @trincot, использование es6 - лучший подход. Но мы можем добавить немного больше сахара, используя оператор спреда, и логическую И короткое замыкание:
const a = {
...(someCondition && {b: 5})
}
Ответ 3
С 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);
Ответ 4
Использование расширенного синтаксиса с логическим значением (как предлагается здесь) не является допустимым синтаксисом. Распространение можно использовать только с итерациями.
Я предлагаю следующее:
const a = {
...(someCondition? {b: 5}: {} )
}
Ответ 5
const obj = {
...(condition) && {someprop: propvalue},
...otherprops
}
Демонстрация в реальном времени:
const obj = {
...(true) && {someprop: 42},
...(false) && {nonprop: "foo"},
...({}) && {tricky: "hello"},
}
console.log(obj);
Ответ 6
Как насчет использования расширенных свойств объекта и только установите свойство, если оно правдиво, например:
[isConditionTrue() && 'propertyName']: 'propertyValue'
Поэтому, если условие не выполняется, оно не создает предпочтительное свойство и, следовательно, вы можете его отменить. См.: http://es6-features.org/#ComputedPropertyNames
ОБНОВЛЕНИЕ: Еще лучше следовать подходу Акселя Раушмайера в своей статье в блоге об условном добавлении записей внутри объектных литералов и массивов (http://2ality.com/2017/04/conditional-literal-entries.html):
const arr = [
...(isConditionTrue() ? [{
key: 'value'
}] : [])
];
const obj = {
...(isConditionTrue() ? {key: 'value'} : {})
};
Мне очень помогли.
Ответ 7
Если цель состоит в том, чтобы объект был самодостаточным и находился в пределах одного набора фигурных скобок, вы можете попробовать следующее:
var a = new function () {
if (conditionB)
this.b = 5;
if (conditionC)
this.c = 5;
if (conditionD)
this.d = 5;
};
Ответ 8
Если вы хотите сделать эту серверную часть (без 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));
Ответ 9
Это уже давно ответили, но, глядя на другие идеи, я придумал интересную производную:
Назначьте значения undefined одному и тому же свойству и затем удалите его
Создайте свой объект с помощью анонимного конструктора и всегда присваивайте членам undefined один и тот же фиктивный элемент, который вы удаляете в самом конце. Это даст вам одну строку (не слишком сложную, надеюсь) на члена + 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;
};
Ответ 10
var a = {
...(condition ? {b: 1} : '') // if condition is true 'b' will be added.
}
Надеюсь, это очень эффективный способ добавить запись, основанную на условии. Дополнительные сведения о том, как условно добавлять записи внутри литералов объектов.
Ответ 11
Я бы сделал это
var a = someCondition ? { b: 5 } : {};
Отредактировано с одной версией кода строки
Ответ 12
Я думаю, что ваш первый подход к добавлению участников условно - это прекрасно. Я не согласен с тем, что не хочу иметь член b
of 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
для редактирования объекта на месте.
Ответ 13
Используя библиотеку 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)
Ответ 14
Вы можете добавить все свои неопределенные значения без каких-либо условий, а затем использовать 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
// }
Ответ 15
Завернуть в объект
Что-то вроде этого немного чище
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))
Ответ 16
Это самое краткое решение, которое я могу предложить:
var a = {};
conditionB && a.b = 5;
conditionC && a.c = 5;
conditionD && a.d = 5;
// ...
Ответ 17
Используя библиотеку lodash, вы можете использовать _.merge
var a = _.merge({}, {
b: conditionB ? 4 : undefined,
c: conditionC ? 5 : undefined,
})
- Если условие
false
и условие a = { c: 5 }
true
, то a = { c: 5 }
- Если оба условия
a = { b: 4, c: 5 }
& conditionC true
, то a = { b: 4, c: 5 }
- Если оба условия B & conditionC
false
, то a = {}