Entfernen Sie leere Eigenschaften / falsche Werte aus dem Objekt mit Underscore.js

82

Ich habe ein Objekt mit mehreren Eigenschaften. Ich möchte alle Eigenschaften entfernen, die falsche Werte haben.

Dies kann mit compactArrays erreicht werden, aber was ist mit Objekten?


quelle
Um zu vermeiden, dass dies über Repositorys hinweg kopiert wird, können Sie Bit zum Importieren dieser Komponente verwenden (die über 3 bestandene Tests und eine MIT-Lizenz verfügt). Sie können auch dieses NPM-Paket ausprobieren (was für eine kleine Komponente ein Overkill sein kann).
Yoni

Antworten:

47

Sie können Ihr eigenes Unterstrich-Plugin (Mixin) erstellen:

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

Und dann verwenden Sie es als native Unterstrichmethode:

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

Aktualisieren

Wie @AndreiNeculau wies darauf hin , wirkt sich dies mixin das ursprüngliche Objekt, während die ursprüngliche compactStrich Methode eine Kopie des Arrays zurückgibt .
Um dieses Problem zu lösen und unser compactObjectVerhalten mehr wie ein Cousin zu verhalten , gibt es hier ein kleines Update:

_.mixin({
  compactObject : function(o) {
     var clone = _.clone(o);
     _.each(clone, function(v, k) {
       if(!v) {
         delete clone[k];
       }
     });
     return clone;
  }
});
gion_13
quelle
1
Da die Frage einen Unterstrich enthält, ist es gut zu erwähnen, dass sich dies nicht so verhält _.compact. Es werden Eigenschaften gelöscht, anstatt einen flachen Klon mit nur wahrheitsgemäßen Werten zu erstellen. Siehe stackoverflow.com/a/19750822/465684 unten
Andrei Neculau
@AndreiNeculau Du hast recht! Ich habe das anscheinend früher verpasst. Siehe meine aktualisierte Antwort.
gion_13
3
Warum zuerst alle Eigenschaften eines Objekts kopieren, dann durchlaufen und falsche fälschen? Das ist nicht performant. Darüber hinaus deletewird generell von der Verwendung abgeraten, da dadurch gleichnamige Eigenschaften aus der Prototypenkette sofort verfügbar gemacht werden und die Leistung aufgrund von "versteckten Klassen" (V8) beeinträchtigt wird. Durch Ändern der Objektstruktur führt die Engine zusätzliche Arbeit aus. Die beste und kürzeste Lösung wäre _.pick(o, _.identity).
Radko Dinev
168

Seit Underscore Version 1.7.0 können Sie Folgendes verwenden _.pick:

_.pick(sourceObj, _.identity)

Erläuterung

Der zweite Parameter _.pickkann eine Prädikatfunktion zum Auswählen von Werten sein. Werte, für die das Prädikat die Wahrheit zurückgibt, werden ausgewählt, und Werte, für die das Prädikat die Wahrheit zurückgibt, werden ignoriert.

wähle _.pick (Objekt, * Schlüssel)

Geben Sie eine Kopie des Objekts zurück , die so gefiltert ist, dass sie nur Werte für die Whitelist- Schlüssel (oder ein Array gültiger Schlüssel) enthält. Akzeptiert alternativ ein Prädikat, das angibt, welche Schlüssel ausgewählt werden sollen.

_.identityist eine Hilfsfunktion, die ihr erstes Argument zurückgibt. Dies bedeutet, dass sie auch als Prädikatfunktion fungiert, die wahrheitsgemäße Werte auswählt und falschwertige Werte ablehnt. Die Unterstreichungsbibliothek enthält auch eine Reihe anderer Prädikate, die beispielsweise _.pick(sourceObj, _.isBoolean)nur boolesche Eigenschaften beibehalten würden.

Wenn Sie diese Technik häufig anwenden, möchten Sie sie möglicherweise etwas ausdrucksvoller gestalten:

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

Unterstrich Version 1.6.0 wurde ebenfalls bereitgestellt _.pick, akzeptierte jedoch keine Prädikatfunktion anstelle einer Whitelist.

Emil Lundberg
quelle
2
Besonderer Dank für die Erwähnung der _.identityFunktion, sehr praktisch.
ivkremer
9
Das war sehr praktisch! Es ist auch möglich _.omit(sourceObj, _.isUndefined), nur undefinierte Werte zu entfernen (false, null, 0 zulassen).
Ben Patterson
1
Es ist auch möglich, pick(obj, Boolean)Falsey-Werte zu eliminieren. Dieselbe Vorgehensweise kann verwendet werden, wenn arr.filter(Boolean)ein Array von Falsey-Werten gereinigt wird ...
David Chase,
3
In ES6 verwandelt sich dies in_.pick(sourceObj, prop => prop)
Deniz Ozger
16
In lodash 4.4.0 _.pickarbeitet mit Eigenschaftsnamen, für diese Funktionalität wie in der _.pickBy
Nachverwendung
45

Schnell und klar: _.omitBy( source, i => !i );

Dies wird in umgekehrter Weise zu Emils Antwort gesagt. Auf diese Weise liest imho klarer; es ist selbsterklärender.

Etwas weniger sauber, wenn Sie nicht den Luxus von ES6 haben: _.omitBy( source, function(i){return !i;});

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

Wenn Sie _.isEmptyanstelle von _.identityWahrhaftigkeit verwenden, werden auch leere Arrays und Objekte bequem aus der Sammlung entfernt und möglicherweise ungünstig Zahlen und Daten entfernt . Daher ist das Ergebnis KEINE genaue Antwort auf die Frage des OP. Es kann jedoch hilfreich sein, wenn leere Sammlungen entfernt werden sollen.

Shwaydogg
quelle
8
In Lodash 4.0 ist diese Funktionalität jetzt unter omitBy. lodash.com/docs#omitBy
JackMorrissey
3
Ich glaube, das ist das gleiche wie: _.pick(source, i => i); was die Negation vermeidet
Jeff Lowery
2
@ JeffLowery Dies ist in Lodash sogar noch besser, da das Standardprädikat die Identitätsfunktion ist! _.pickBy(source)ist alles was benötigt wird.
Shibumi
21

Mit lodashs Verwandlung ,

_.transform(obj, function(res, v, k) {
  if (v) res[k] = v;
});
raine
quelle
23
Whit Lodashs Pick (obj, Identität); kürzer ^ _ ^
böse
Diese Antwort oder der Kommentar von @ evilive darunter ist die Antwort.
Radko Dinev
2
Eine kürzere Variante, basierend auf dem obigen Kommentar, wärevar compactObject = _.partialRight(_.pick, _.identity);
Zaboco
yse, _.pickBy(object)ist alles was Sie brauchen
wdetac
18
Object.keys(o).forEach(function(k) {
    if (!o[k]) {
        delete o[k];
    }
});
Florian Margaine
quelle
1
Und man kann Unterstriche für .keysund verwenden .forEach.
Felix Kling
Wie würde das dann in Underscore aussehen? Der Versuch, es zusammenzusetzen…
+1 das ist ein großartiger Mann. Bitte geben Sie mir den Link der forEachMethode von JS
diEcho
9

Sie können einen flachen Klon erstellen:

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

für Objektgebrauch löschen.

for(var k in obj){

  if(obj.hasOwnProperty(k) && !obj[k]){
    delete obj[k];
  }
}
Anoop
quelle
Da er eine Unterstrichlösung wünscht, können Sie das Array mit einer der Unterstrichmethoden
durchlaufen
5

Plötzlich musste ich eine Funktion erstellen, um rekursiv Fälschungen zu entfernen. Ich hoffe das hilft. Ich benutze 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 });

Dann können Sie es verwenden:

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
quelle
1

So ergänzen Sie die Antwort von gion_13:

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

Dieser erstellt ein neues Objekt und fügt Schlüssel und Werte hinzu, anstatt alles zu klonen und Schlüssel-Wert-Paare zu löschen. Kleiner Unterschied.

Noch wichtiger ist jedoch, dass explizit nach null und undefiniert anstelle von falsey gesucht wird, wodurch Schlüssel-Wert-Paare gelöscht werden, deren Wert false ist.

Geoff Lee
quelle
0

in der lodash gefällt dir das:

_.pickBy(object, _.identity);
Hossein Rezaei
quelle
-1

Obwohl _.compactfür die Verwendung in Arrays dokumentiert ist. Es scheint auch für Objekte zu funktionieren. Ich habe gerade Folgendes in Chrome-, Opern- und Firefox-Konsolen ausgeführt:

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

[1, 3, function()]

UPDATE: Wie aus dem Beispiel hervorgeht, werden beim Aufrufen _.compacteines Objekts die Schlüssel gelöscht und ein komprimiertes Array zurückgegeben.

tzvi
quelle
1
Es wird jedoch immer noch ein Array zurückgegeben. Die Schlüssel sind verloren.
Turadg
1
Du hast recht. Lösche ich dann meine Antwort? Oder bevorzugt Stackoverflow etwas anderes?
Tzvi
2
Ich kenne keine Community-Präferenz, aber wenn Sie damit einverstanden sind, könnte es sinnvoll sein, zu verhindern, dass jemand anderes eine ähnliche Antwort hinzufügt.
Turadg