Видаліть порожні властивості / хибні значення з Object за допомогою Underscore.js


83

У мене є об’єкт з декількома властивостями. Я хотів би видалити будь-які властивості, що мають хибні значення.

Цього можна досягти за допомогою compactмасивів, а як щодо об’єктів?


Щоб уникнути копіювання цього в репозиторії, ви можете використовувати Bit для імпорту цього компонента (який має 3 проходження тесту та ліцензію MIT). Ви також можете спробувати цей пакет NPM (що може бути надмірним для невеликого компонента).
Йоні,

Відповіді:


47

Ви можете створити власний плагін підкреслення (mixin):

_.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 нижче
Андрій Некула,

@AndreiNeculau Ви маєте рацію! Здається, я раніше цього пропустив. Дивіться мою оновлену відповідь.
gion_13

3
Навіщо спочатку копіювати всі властивості об’єкта, потім перебирати їх і видаляти хибні? Це непродуктивно. Більше того, використання, deleteяк правило, не рекомендується, оскільки воно негайно виставляє властивості з тією ж назвою з ланцюжка прототипів, а також шкодить продуктивності через "приховані класи" (V8) - зміна структури об'єкта змушує двигун робити додаткову роботу. Найкращим і найкоротшим рішенням буде _.pick(o, _.identity).
Радко Дінев

170

З версії Underscore 1.7.0 ви можете використовувати _.pick:

_.pick(sourceObj, _.identity)

Пояснення

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

pick _.pick (об'єкт, * ключі)

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

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

Якщо ви багато використовуєте цю техніку, можливо, ви хочете зробити її трохи виразнішою:

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

Також передбачена версія підкреслення 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)
Deniz Ozger

16
В lodash 4.4.0 _.pickпрацює з іменами властивостей, для цієї функціональності, як згадувалося в _.pickBy
поствикористанні

45

Швидке очищення: _.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

3
Я вважаю, що це те саме, _.pick(source, i => i); що уникає заперечення
Джеф Лоурі

2
@JeffLowery Це ще краще в Lodash, оскільки предикат за замовчуванням - це функція ідентичності! _.pickBy(source)це все, що потрібно.
Шибумі

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

21

З перетворенням Лодаша ,

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

23
нічого лодаша _.pick (obj, _.identity); коротше ^ _ ^
вижити

Ця відповідь або коментар @ evilive під ним - це відповідь.
Радко Дінев

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


yse, _.pickBy(object)це все, що тобі потрібно
wdetac

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

1
І можна використовувати підкреслення для .keysі .forEach.
Фелікс Клінг,

Тоді як би це виглядало в Підкресленнях? Намагаюся скласти це ...

+1 це чудовий чоловік. будь ласка, дайте мені посилання на forEachметод JS
diEcho



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

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