Usuń puste właściwości / fałszywe wartości z obiektu za pomocą Underscore.js


84

Mam obiekt z kilkoma właściwościami. Chciałbym usunąć wszystkie właściwości, które mają fałszywe wartości.

Można to osiągnąć za compactpomocą tablic, ale co z obiektami?


Aby uniknąć kopiowania i wklejania tego między repozytoriami, możesz użyć Bit do zaimportowania tego komponentu (który ma zaliczone 3 testy i licencję MIT). Możesz także wypróbować ten pakiet NPM (co może być przesadą w przypadku małego komponentu).
Yoni

Odpowiedzi:


47

Możesz stworzyć własną wtyczkę podkreślenia (mixin):

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

A potem użyj go jako natywnej metody podkreślenia:

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

Aktualizacja

Jak zauważył @AndreiNeculau , ta mieszanka wpływa na oryginalny obiekt, podczas gdy oryginalna metoda podkreślenia zwraca kopię tablicy . Aby rozwiązać ten problem i sprawić, by nasz zachowywał się bardziej jak kuzyn , oto drobna aktualizacja:compact
compactObject

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

1
Ponieważ pytanie ma odniesienie do podkreślenia, dobrze byłoby wspomnieć, że to nie zachowuje się jak _.compact. Usunie właściwości, a nie utworzy płytki klon tylko z prawdziwymi wartościami. Zobacz stackoverflow.com/a/19750822/465684 poniżej
Andrei Neculau

@AndreiNeculau Masz rację! Wydaje mi się, że przegapiłem to wcześniej. Zobacz moją zaktualizowaną odpowiedź.
gion_13

3
Po co najpierw kopiować wszystkie właściwości obiektu, a następnie przeglądać je w pętli i usuwać fałszywe? To nieskuteczne. Co więcej, używanie deletejest generalnie odradzane, ponieważ natychmiast ujawnia właściwości o tej samej nazwie z łańcucha prototypów, a także zmniejsza wydajność z powodu „ukrytych klas” (V8) - zmiana struktury obiektu powoduje, że silnik wykonuje dodatkową pracę. Najlepszym i najkrótszym rozwiązaniem byłoby _.pick(o, _.identity).
Radko Dinev,

171

Od wersji Underscore 1.7.0 możesz używać _.pick:

_.pick(sourceObj, _.identity)

Wyjaśnienie

Drugi parametr _.pickmoże być funkcją predykatu do wybierania wartości. Wartości, dla których predykat zwraca prawdę, są wybierane, a wartości, dla których predykat zwraca fałsz, są ignorowane.

pick _.pick (obiekt, * klucze)

Zwróć kopię obiektu , przefiltrowaną, aby zawierała tylko wartości dla kluczy z białej listy (lub tablicy prawidłowych kluczy). Alternatywnie akceptuje predykat wskazujący, które klucze wybrać.

_.identityjest funkcją pomocniczą, która zwraca swój pierwszy argument, co oznacza, że ​​działa również jako funkcja predykatu, która wybiera prawdziwe wartości i odrzuca fałszywe. Biblioteka Underscore zawiera również kilka innych predykatów, na przykład _.pick(sourceObj, _.isBoolean)zachowuje tylko właściwości logiczne.

Jeśli często używasz tej techniki, możesz uczynić ją nieco bardziej wyrazistą:

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

Podkreślona wersja 1.6.0 również została udostępniona _.pick, ale nie akceptowała funkcji predykatu zamiast białej listy.


2
Specjalne podziękowania za wspomnienie _.identityfunkcji, bardzo przydatne.
ivkremer

9
To było niezwykle przydatne! Można również użyć _.omit(sourceObj, _.isUndefined)do usunięcia tylko niezdefiniowanych wartości (dopuszczając false, null, 0).
Ben Patterson,

1
Jest również możliwe do zrobienia pick(obj, Boolean), aby wyeliminować wartości falsey że samo podejście może być stosowane, gdy arr.filter(Boolean)wyczyścić tablicę z wartościami falsey ...
David Chase

3
W ES6 zmienia się to w_.pick(sourceObj, prop => prop)
Deniz Ozger

16
W lodash 4.4.0 _.pickdziała z nazwami nieruchomości, dla tej funkcji, jak wspomniano w postu_.pickBy
zooblin

46

Szybkie i jasne: _.omitBy( source, i => !i );

Stwierdzono to w sposób odwrotny do odpowiedzi Emila. W ten sposób imho czyta jaśniej; jest to bardziej oczywiste.

Nieco mniej czyste, jeśli nie masz luksusu ES6: _.omitBy( source, function(i){return !i;});

Alternatywny: _.omitBy( source, _.isEmpty)

Używanie _.isEmptyzamiast _.identityprawdziwości w wygodny sposób usunie również puste tablice i obiekty z kolekcji i być może niewygodnie usunie liczby i daty . Tak więc wynik NIE jest dokładną odpowiedzią na pytanie PO, jednak może być przydatny przy próbie usunięcia pustych kolekcji.


8
W Lodash 4.0 ta funkcja jest teraz dostępna omitBy. lodash.com/docs#omitBy
JackMorrissey,

3
Uważam, że jest to to samo, co: _.pick(source, i => i); co unika negacji
Jeff Lowery,

2
@JeffLowery To jest jeszcze lepsze w Lodash, ponieważ domyślnym predykatem jest funkcja tożsamości! _.pickBy(source)to wszystko, czego potrzeba.
Shibumi,

Uwaga: liczby są uważane za puste. _.isEmpty(5) === true. W ten sposób wartości, które są liczbami, zostaną odrzucone.
Sir Nathan Stassen

21

Z transformacją lodash ,

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

23
whit lodash's _.pick (obj, _.identity); krótszy ^ _ ^
zły

Ta odpowiedź lub komentarz @ evilive pod nią JEST odpowiedzią.
Radko Dinev,

2
krótsza odmiana, oparta na powyższym komentarzu, tovar compactObject = _.partialRight(_.pick, _.identity);
zaboco


yse, _.pickBy(object)to wszystko, czego potrzebujesz
wdetac


9

Możesz stworzyć płytki klon:

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

5

do użytku obiektu usuń.

for(var k in obj){

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

ponieważ chce rozwiązania podkreślającego, możesz iterować po tablicy za pomocą jednej z metod podkreślenia
gion_13

5

Nagle potrzebowałem stworzyć funkcję usuwającą rekurencyjne falsyfikaty. Mam nadzieję, że to pomoże. Używam 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 });

Następnie możesz go użyć:

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

Aby dodać do odpowiedzi gion_13:

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

Ten tworzy nowy obiekt i dodaje klucze i wartości zamiast klonować wszystko i usuwać pary klucz-wartość. Niewielka różnica.

Ale co ważniejsze, sprawdza jawnie pod kątem wartości null i undefined zamiast falsey, co spowoduje usunięcie par klucz-wartość, które mają wartość false.



-1

Chociaż _.compactjest udokumentowane do użycia w tablicach. Wydaje się, że działa również w przypadku obiektów. Właśnie uruchomiłem na konsolach Chrome, Opera i Firefox:

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

[1, 3, function()]

UPDATE: Jak wskazuje przykład, wywołanie _.compactobiektu spowoduje porzucenie kluczy i zwrócenie skompaktowanej tablicy.


1
Ale nadal zwraca tablicę. Klucze są zgubione.
Turadg

1
Masz rację. Czy w takim razie usuwam swoją odpowiedź? A może stackoverflow woli coś innego?
tzvi

2
Nie znam preferencji społeczności, ale jeśli nie przeszkadza ci to odejście, może to mieć wartość uniemożliwiającą komuś dodanie podobnej odpowiedzi.
Turadg
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.