В 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,
})
  1. Если условие false и условие a = { c: 5 } true, то a = { c: 5 }
  2. Если оба условия a = { b: 4, c: 5 } & conditionC true, то a = { b: 4, c: 5 }
  3. Если оба условия B & conditionC false, то a = {}