Eliminar propiedades vacías / valores falsos de Object con Underscore.js

83

Tengo un objeto con varias propiedades. Me gustaría eliminar cualquier propiedad que tenga valores falsos.

Esto se puede lograr con compactmatrices, pero ¿qué pasa con los objetos?


fuente
Para evitar copiar y pegar esto en los repositorios, puede usar Bit para importar este componente (que tiene 3 pruebas aprobadas y licencia MIT). También puede probar este paquete de NPM (que podría ser una exageración para un componente pequeño).
Yoni

Respuestas:

47

Puede crear su propio complemento de subrayado (mixin):

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

Y luego úselo como un método de subrayado nativo:

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

Actualizar

Como señaló @AndreiNeculau , este mixin afecta al objeto original, mientras que el método de subrayado original devuelve una copia de la matriz . Para resolver este problema y hacer que nos comportemos más como su primo , aquí hay una actualización menor:compact
compactObject

_.mixin({
  compactObject : function(o) {
     var clone = _.clone(o);
     _.each(clone, function(v, k) {
       if(!v) {
         delete clone[k];
       }
     });
     return clone;
  }
});
gion_13
fuente
1
Dado que la pregunta tiene una referencia de subrayado, sería bueno mencionar que esto no se comporta como _.compact. Eliminará propiedades, en lugar de crear un clon superficial solo con valores veraces. Ver stackoverflow.com/a/19750822/465684 a continuación
Andrei Neculau
@AndreiNeculau ¡Tienes razón! Parece que me lo he perdido antes. Vea mi respuesta actualizada.
gion_13
3
¿Por qué primero copiar todas las propiedades de un objeto, luego recorrerlas y eliminar las falsas? Eso no funciona. Además, deletegeneralmente se desaconseja el uso, ya que expone inmediatamente las propiedades con el mismo nombre de la cadena del prototipo y también perjudica el rendimiento debido a las "clases ocultas" (V8): cambiar la estructura del objeto hace que el motor haga un trabajo adicional. La mejor y más corta solución sería _.pick(o, _.identity).
Radko Dinev
170

Desde la versión 1.7.0 de Underscore, puede usar _.pick:

_.pick(sourceObj, _.identity)

Explicación

El segundo parámetro _.pickpuede ser una función de predicado para seleccionar valores. Se seleccionan los valores para los que el predicado devuelve veracidad y los valores para los que el predicado devuelve falsedad se ignoran.

pick _.pick (objeto, * claves)

Devuelve una copia del objeto , filtrado para tener solo valores para las claves en la lista blanca (o una matriz de claves válidas). También acepta un predicado que indica qué claves elegir.

_.identityes una función auxiliar que devuelve su primer argumento, lo que significa que también funciona como una función de predicado que selecciona valores verdaderos y rechaza los falsos. La biblioteca Underscore también viene con un montón de otros predicados, por ejemplo _.pick(sourceObj, _.isBoolean), solo retendría propiedades booleanas.

Si usa mucho esta técnica, es posible que desee hacerla un poco más expresiva:

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

_.pickTambién se proporcionó la versión 1.6.0 de subrayado , pero no aceptó una función de predicado en lugar de una lista blanca.

Emil Lundberg
fuente
2
Un agradecimiento especial por mencionar la _.identityfunción, muy útil.
ivkremer
9
¡Esto ha sido muy útil! También se puede usar _.omit(sourceObj, _.isUndefined)para eliminar solo valores no definidos (permitiendo falso, nulo, 0).
Ben Patterson
1
También es posible hacer pick(obj, Boolean)para eliminar los valores de falsey, ese mismo enfoque se puede usar cuando se arr.filter(Boolean)limpia una matriz de valores de falsey ...
David Chase
3
En ES6, esto se convierte en_.pick(sourceObj, prop => prop)
Deniz Ozger
16
En lodash 4.4.0 _.pickfunciona con nombres de propiedad, para esta funcionalidad como se menciona en el uso posterior_.pickBy
zooblin
45

Rápido y claro: _.omitBy( source, i => !i );

Esto se expresa de manera inversa a la respuesta de Emil. De esta manera, en mi humilde opinión, lee más claro; se explica más por sí mismo.

Un poco menos limpio si no tiene el lujo de ES6: _.omitBy( source, function(i){return !i;});

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

El uso _.isEmpty, en lugar de la _.identityveracidad, también eliminará convenientemente matrices y objetos vacíos de la colección y quizás eliminará números y fechas de manera inconveniente . Por lo tanto, el resultado NO es una respuesta exacta a la pregunta del OP, sin embargo, podría ser útil cuando se busca eliminar colecciones vacías.

Shwaydogg
fuente
8
En Lodash 4.0, esta funcionalidad está ahora bajo omitBy. lodash.com/docs#omitBy
JackMorrissey
3
Creo que esto es lo mismo que: lo _.pick(source, i => i); que evita la negación
Jeff Lowery
2
@JeffLowery ¡Esto es aún mejor, en Lodash, porque el predicado predeterminado es la función de identidad! _.pickBy(source)es todo lo que se necesita.
Shibumi
Nota: los números se consideran vacíos. _.isEmpty(5) === true. Por tanto, los valores que son números se eliminarán.
Sir Nathan Stassen
21

Con la transformación de Lodash ,

_.transform(obj, function(res, v, k) {
  if (v) res[k] = v;
});
llover
fuente
23
con _.pick de Lodash (obj, _.identity); más corto ^ _ ^
malvado
Esta respuesta o el comentario de @ evilive ES la respuesta.
Radko Dinev
2
una variación más corta, basada en el comentario anterior, seríavar compactObject = _.partialRight(_.pick, _.identity);
zaboco
sí, _.pickBy(object)es todo lo que necesita
wdetac
19
Object.keys(o).forEach(function(k) {
    if (!o[k]) {
        delete o[k];
    }
});
Florian Margaine
fuente
1
Y se puede usar subrayado para .keysy .forEach.
Felix Kling
¿Cómo se vería esto en Underscore, entonces? Intentando reconstruirlo…
+1 este es un hombre increíble. por favor, dame el enlace del forEachmétodo de JS
diEcho
9

Puede crear un clon superficial:

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

para eliminar el uso de objetos.

for(var k in obj){

  if(obj.hasOwnProperty(k) && !obj[k]){
    delete obj[k];
  }
}
Anoop
fuente
dado que quiere una solución de subrayado, puede iterar sobre la matriz utilizando uno de los métodos de subrayado
gion_13
5

De repente, necesitaba crear una función para eliminar las falsificaciones de forma recursiva. Espero que esto ayude. Estoy usando 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 });

Entonces puedes usarlo:

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

Para agregar a la respuesta de gion_13:

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

Éste crea un nuevo objeto y agrega claves y valores en lugar de clonar todo y eliminar pares clave-valor. Diferencia menor.

Pero lo que es más importante, comprueba explícitamente si hay nulos e indefinidos en lugar de falsey, lo que eliminará los pares clave-valor que tengan falso como valor.

Geoff Lee
fuente
0

en el lodash te gusta esto:

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

Aunque _.compactestá documentado para su uso en matrices. También parece funcionar para objetos. Acabo de ejecutar lo siguiente en las consolas Chrome, Opera y Firefox:

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

[1, 3, function()]

ACTUALIZACIÓN: como indica el ejemplo, la llamada _.compacta un objeto soltará las claves y devolverá una matriz compactada.

tzvi
fuente
1
Pero todavía devuelve una matriz. Las llaves se pierden.
Turadg
1
Tienes razón. ¿Borro mi respuesta entonces? ¿O stackoverflow prefiere algo más?
tzvi
2
No conozco una preferencia de la comunidad, pero si está de acuerdo con irse, podría tener el valor de evitar que otra persona agregue una respuesta similar.
Turadg