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?


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;
  }
});

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.


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.


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;
});

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


9

Puede crear un clon superficial:

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

5

para eliminar el uso de objetos.

for(var k in obj){

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

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'
//   }
// }

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.



-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.


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.