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?


źródło
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;
  }
});
gion_13
źródło
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.

Emil Lundberg
źródło
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.

Shwaydogg
źródło
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;
});
Raine
źródło
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
19
Object.keys(o).forEach(function(k) {
    if (!o[k]) {
        delete o[k];
    }
});
Florian Margaine
źródło
1
I można użyć podkreślenia dla .keysi .forEach.
Felix Kling
Jak by to wyglądało w Underscore? Próbuję to poskładać…
+1 to jest niesamowity człowiek. proszę o link do forEachmetody JS
diEcho
9

Możesz stworzyć płytki klon:

_(obj).reduce(function(a,v,k){ 
     if(v){ a[k]=v; } 
     return a; 
},{});
webwise
źródło
5

do użytku obiektu usuń.

for(var k in obj){

  if(obj.hasOwnProperty(k) && !obj[k]){
    delete obj[k];
  }
}
Anoop
źródło
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'
//   }
// }
Marco Godínez
źródło
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.

Geoff Lee
źródło
0

w lodash robisz to tak:

_.pickBy(object, _.identity);
Hossein Rezaei
źródło
-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.

tzvi
źródło
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