Удалите пустые свойства / ложные значения из объекта с помощью Underscore.js


84

У меня есть объект с несколькими свойствами. Я хочу удалить все свойства с ложными значениями.

Этого можно добиться с помощью compactмассивов, но как насчет объектов?


Чтобы избежать копирования в репозитории, вы можете использовать Bit для импорта этого компонента (который имеет 3 прохождения теста и лицензию MIT). Вы также можете попробовать этот пакет NPM (который может оказаться излишним для небольшого компонента).
Йони

Ответы:


47

Вы можете создать свой собственный плагин подчеркивания (миксин):

_.mixin({
  compactObject: function(o) {
    _.each(o, function(v, k) {
      if(!v) {
        delete o[k];
      }
    });
    return o;
  }
});

А затем используйте его как собственный метод подчеркивания:

var o = _.compactObject({
  foo: 'bar',
  a: 0,
  b: false,
  c: '',
  d: null,
  e: undefined
});

Обновить

Как указал @AndreiNeculau , этот миксин влияет на исходный объект, в то время как исходный метод подчеркивания возвращает копию массива . Чтобы решить эту проблему и заставить нас вести себя как кузен , вот небольшое обновление:compact
compactObject

_.mixin({
  compactObject : function(o) {
     var clone = _.clone(o);
     _.each(clone, function(v, k) {
       if(!v) {
         delete clone[k];
       }
     });
     return clone;
  }
});

1
Поскольку в вопросе есть ссылка на подчеркивание, было бы хорошо упомянуть, что это не ведет себя как _.compact. Он удалит свойства, а не создаст мелкий клон только с истинными значениями. См stackoverflow.com/a/19750822/465684 ниже
Андрей Neculau

@AndreiNeculau Вы правы! Кажется, я раньше это упустил. Смотрите мой обновленный ответ.
gion_13 05

3
Зачем сначала копировать все свойства объекта, а затем перебирать их и удалять ложные? Это неэффективно. Более того, использование deleteобычно не рекомендуется, поскольку оно сразу же предоставляет свойства с тем же именем из цепочки прототипов, а также снижает производительность из-за «скрытых классов» (V8) - изменение структуры объекта заставляет движок выполнять дополнительную работу. Лучшее и самое короткое решение было бы _.pick(o, _.identity).
Радько Динев

171

Начиная с версии Underscore 1.7.0, вы можете использовать _.pick:

_.pick(sourceObj, _.identity)

Объяснение

Второй параметр _.pickможет быть функцией предиката для выбора значений. Выбираются значения, для которых предикат возвращает истинность , а значения, для которых предикат возвращает ложь , игнорируются.

pick _.pick (объект, * ключи)

Вернуть копию объекта , отфильтрованную, чтобы иметь значения только для ключей из белого списка (или массива допустимых ключей). В качестве альтернативы принимает предикат, указывающий, какие ключи выбрать.

_.identity- это вспомогательная функция, которая возвращает свой первый аргумент, что означает, что она также работает как функция-предикат, которая выбирает истинные значения и отклоняет ложные. Библиотека Underscore также поставляется с множеством других предикатов, например _.pick(sourceObj, _.isBoolean), сохранит только логические свойства.

Если вы часто используете эту технику, возможно, вы захотите сделать ее более выразительной:

var pickNonfalsy = _.partial(_.pick, _, _.identity); // Place this in a library module or something
pickNonfalsy(sourceObj);

Также предоставляется Underscore версии 1.6.0 _.pick, но она не принимает функцию предиката вместо белого списка.


2
Отдельное спасибо за упоминание _.identityфункции, очень удобно.
ivkremer

9
Это было очень удобно! Также можно использовать _.omit(sourceObj, _.isUndefined)для удаления только неопределенных значений (допускающих false, null, 0).
Бен Паттерсон

1
Также можно сделать pick(obj, Boolean)для устранения ложных значений тот же подход, который можно использовать при arr.filter(Boolean)очистке массива от ложных значений ...
Дэвид Чейз

3
В ES6 это превращается в_.pick(sourceObj, prop => prop)
Дениз Озгер

16
В lodash 4.4.0 _.pickработает с именами свойств, для этой функции, как указано в посте, используется_.pickBy
zooblin

46

Быстро и ясно: _.omitBy( source, i => !i );

Это сказано обратным ответу Эмиля. Таким образом imho читается яснее; это более понятно.

Чуть менее чистый, если у вас нет роскоши ES6: _.omitBy( source, function(i){return !i;});

Альтернативный: _.omitBy( source, _.isEmpty)

Использование _.isEmptyвместо _.identityправдивости также удобно удаляет из коллекции пустые массивы и объекты и, возможно, неудобно удаляет числа и даты . Таким образом, результат НЕ является точным ответом на вопрос OP, однако он может быть полезен при удалении пустых коллекций.


8
В Lodash 4.0 эта функциональность теперь недоступна omitBy. lodash.com/docs#omitBy
JackMorrissey 05

3
Я считаю, что это то же самое, что и: _.pick(source, i => i); что позволяет избежать отрицания
Джефф Лоури

2
@JeffLowery В Lodash это даже лучше, потому что предикатом по умолчанию является функция идентификации! _.pickBy(source)это все, что нужно.
Shibumi

Примечание: числа считаются пустыми. _.isEmpty(5) === true. Таким образом значения, которые являются числами, будут отброшены.
Сэр Натан Стассен

21

С преобразованием lodash ,

_.transform(obj, function(res, v, k) {
  if (v) res[k] = v;
});

23
_.pick от lodash (obj, _.identity); короче ^ _ ^
evilive 09

Этот ответ или комментарий @ evilive под ним - это ответ.
Radko Dinev

2
более короткий вариант, основанный на вышеприведенном комментарии, будетvar compactObject = _.partialRight(_.pick, _.identity);
zaboco 08


yse, _.pickBy(object)это все, что вам нужно
wdetac

19
Object.keys(o).forEach(function(k) {
    if (!o[k]) {
        delete o[k];
    }
});

1
И можно использовать подчеркивание для .keysи .forEach.
Феликс Клинг

Как тогда это будет выглядеть в Underscore? Пытаюсь собрать все воедино…

+1 это классный мужик. дайте пожалуйста ссылку на forEachметод JS
diEcho


9

Вы можете создать неглубокий клон:

_(obj).reduce(function(a,v,k){ 
     if(v){ a[k]=v; } 
     return a; 
},{});

5

для объекта используйте удаление.

for(var k in obj){

  if(obj.hasOwnProperty(k) && !obj[k]){
    delete obj[k];
  }
}

поскольку ему нужно решение с подчеркиванием, вы можете перебирать массив, используя один из методов подчеркивания
gion_13,

5

Внезапно мне потребовалось создать функцию для удаления рекурсивных фальсификаций. Надеюсь, это поможет. Я использую Lodash.

var removeFalsies = function (obj) {
    return _.transform(obj, function (o, v, k) {
        if (v && typeof v === 'object') {
            o[k] = _.removeFalsies(v);
        } else if (v) {
            o[k] = v;
        }
    });
};

_.mixin({ 'removeFalsies': removeFalsies });

Тогда вы можете использовать это:

var o = _.removeFalsies({
  foo: 'bar',
  a: 0,
  b: false,
  c: '',
  d: null,
  e: undefined,
  obj: {
    foo: 'bar',
    a: 0,
    b: false,
    c: '',
    d: null,
    e: undefined
  }
});

// {
//   foo: 'bar',
//   obj: {
//     foo: 'bar'
//   }
// }

1

Чтобы добавить к ответу gion_13:

_.mixin({
  compactObject : function(o) {
     var newObject = {};
     _.each(o, function(v, k) {
       if(v !== null && v !== undefined) {
         newObject[k] = v
       }
     });
     return newObject;
  }
});

Он создает новый объект и добавляет ключи и значения вместо клонирования всего и удаления пар ключ-значение. Незначительная разница.

Но что еще более важно, он явно проверяет наличие null и undefined вместо falsey, что удаляет пары ключ-значение, которые имеют значение false.



-1

Хотя _.compactзадокументирован для использования в массивах. Кажется, это работает и для объектов. Я только что запустил следующее в консолях chrome, opera и firefox:

var obj = {first: 1, second: null, third: 3, fourth: function(){return 5}}
undefined
_.compact(obj)

[1, 3, function()]

ОБНОВЛЕНИЕ: как показано в образце, вызов _.compactобъекта приведет к удалению ключей и возврату сжатого массива.


1
Но он по-прежнему возвращает массив. Ключи потеряны.
Turadg

1
Вы правы. Могу ли я тогда удалить свой ответ? Или stackoverflow предпочитает что-то другое?
tzvi 05

2
Я не знаю предпочтений сообщества, но если вы согласны с тем, чтобы уйти, это может иметь значение, чтобы помешать кому-либо добавить аналогичный ответ.
Turadg 06
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.