Remover atributos em branco de um objeto em Javascript

266

Como removo todos os atributos que estão undefinedou estão nullem um objeto JavaScript?

(A pergunta é semelhante a esta para matrizes)

abhijit
fonte
19
Sugiro que as pessoas ignoram o top-rank e mudança para as versões ES6 / ES7 aqui, stackoverflow.com/a/38340730/124486
Evan Carroll
2
Também ES6 forros sem mutação objeto está aqui: stackoverflow.com/a/57625661/1602301
galinhas

Respostas:

184

Você pode percorrer o objeto:

var test = {
    test1 : null,
    test2 : 'somestring',
    test3 : 3,
}

function clean(obj) {
  for (var propName in obj) { 
    if (obj[propName] === null || obj[propName] === undefined) {
      delete obj[propName];
    }
  }
}

clean(test);

Se você estiver preocupado com a remoção dessa propriedade que não está executando a cadeia de tipos de objeto do objeto, você também pode:

function clean(obj) {
  var propNames = Object.getOwnPropertyNames(obj);
  for (var i = 0; i < propNames.length; i++) {
    var propName = propNames[i];
    if (obj[propName] === null || obj[propName] === undefined) {
      delete obj[propName];
    }
  }
}

Algumas notas sobre nulo vs indefinido:

test.test1 === null; // true
test.test1 == null; // true

test.notaprop === null; // false
test.notaprop == null; // true

test.notaprop === undefined; // true
test.notaprop == undefined; // true
Owen
fonte
2
Adicionada uma correção rápida. A variável "i" não declarada vazaria para o escopo externo se esse trecho fosse usado em uma função.
Eric Nguyen
4
você pode simplificar o (teste [i] === nula || teste [i] === indefinido) para (teste [i] == null)
jaf0
Olá, @EricNguyen, diferentemente do C e de outras linguagens, o javascript não possui escopo de bloco para variáveis ​​(apenas escopo de função); portanto, a variável i sempre vazará no escopo após o bloco for .
Gerardo Lima
1
@GerardoLima, sim. Eu estava assumindo que tudo isso seria envolvido em uma função. O que eu quis dizer (supondo que tudo isso esteja envolvido com uma função) é que você precisa da declaração var ou eu vazarei mesmo fora do escopo da função.
Eric Nguyen
Isso também passará pelo protótipo do objeto primitivo - que na maioria dos casos não é desejado. stackoverflow.com/a/2869372/1612318
Rotareti
427

Usando alguns ES6 / ES2015 :

1) Uma linha simples para remover os itens em linha sem atribuição:

Object.keys(myObj).forEach((key) => (myObj[key] == null) && delete myObj[key]);

jsbin

2) Este exemplo foi removido ...

3) Primeiro exemplo escrito como uma função:

const removeEmpty = obj => {
  Object.keys(obj).forEach(key => obj[key] == null && delete obj[key]);
};

jsbin

4) Esta função também utiliza recursão para excluir itens de objetos aninhados:

const removeEmpty = obj => {
  Object.keys(obj).forEach(key => {
    if (obj[key] && typeof obj[key] === "object") removeEmpty(obj[key]); // recurse
    else if (obj[key] == null) delete obj[key]; // delete
  });
};

jsbin

4b) É semelhante a 4), mas em vez de alterar o objeto de origem diretamente, ele retorna um novo objeto.

const removeEmpty = obj => {
  const newObj = {};

  Object.keys(obj).forEach(key => {
    if (obj[key] && typeof obj[key] === "object") {
      newObj[key] = removeEmpty(obj[key]); // recurse
    } else if (obj[key] != null) {
      newObj[key] = obj[key]; // copy value
    }
  });

  return newObj;
};

5) Uma abordagem funcional para 4b) com base na resposta de @ MichaelJ.Zoidl usando filter()e reduce(). Este também retorna um novo objeto:

const removeEmpty = obj =>
  Object.keys(obj)
    .filter(k => obj[k] != null) // Remove undef. and null.
    .reduce(
      (newObj, k) =>
        typeof obj[k] === "object"
          ? { ...newObj, [k]: removeEmpty(obj[k]) } // Recurse.
          : { ...newObj, [k]: obj[k] }, // Copy value.
      {}
    );

jsbin

6) O mesmo que 4), mas com o ES7 / 2016 Object.entries() .

const removeEmpty = (obj) => 
  Object.entries(obj).forEach(([key, val]) => {
    if (val && typeof val === 'object') removeEmpty(val)
    else if (val == null) delete obj[key]
})

5b) Outra versão funcional que usa recursão e retorna um novo objeto com o ES2019 Object.fromEntries() :

const removeEmpty = obj =>
  Object.fromEntries(
    Object.entries(obj)
      .filter(([k, v]) => v != null)
      .map(([k, v]) => (typeof v === "object" ? [k, removeEmpty(v)] : [k, v]))
  );

7) O mesmo que 4), mas na planície ES5 :

function removeEmpty(obj) {
  Object.keys(obj).forEach(function(key) {
    if (obj[key] && typeof obj[key] === 'object') removeEmpty(obj[key])
    else if (obj[key] == null) delete obj[key]
  });
};

jsbin

Rotareti
fonte
3
@AugustinRiedinger Quando tenho que decidir entre uma quebra de linha e uma abreviação, às vezes vou para a abreviação se achar que a abreviação é o mal menor. O código em 5) não é difícil de raciocinar e é uma função que remove vazio keysde um object, portanto, oe ké óbvio. Mas acho que é uma questão de gosto.
Rotareti
3
Primeira versão com sabor ES5:Object.keys(myObj).forEach(function (key) {(myObj[key] == null) && delete myObj[key]});
Neurotransmissor
1
Uma linha, sem função:Object.entries(myObj).reduce((acc, [key, val]) => { if (val) acc[key] = val; return acc; }, {})
Paul Slm 10/10
7
Como estamos tentando ser minuciosos, pode ser bom ver uma solução imutável. Eles estão mudando o objeto de origem e, enganosamente, retornando o objeto que é realmente desnecessário porque o objeto foi mutado. Os iniciantes capturam o valor do objeto retornado e se perguntam por que o objeto de origem também é modificado.
Mike McLin
2
5) Não funciona com matrizes (Object.keys retornará os números de posição da matriz como a chave para os elementos). Possivelmente outros têm este problema, mas eu achei isso quando testando 5.
Eelco
95

Se você estiver usando lodash ou underscore.js, aqui está uma solução simples:

var obj = {name: 'John', age: null};

var compacted = _.pickBy(obj);

Isso funcionará apenas com lodash 4, pré lodash 4 ou underscore.js, use _.pick(obj, _.identity);

Ben
fonte
1
Brilhante! Obrigado! Para sua informação, o que não era óbvio para mim é que você também poderia usá-lo assim: foo (). Then (_. PickBy); // filtrando resultados vazios
Maciej Gurban
29
Observe que isso não terá o resultado desejado se o objeto contiver valores falsos, como 0 ou cadeias vazias. Então _.omit(obj, _.isUndefined)é melhor.
JHH 23/05
5
@JHH _.isUndefinednão omite nulos, use _.omitBy(obj, _.isNil)para omitir ambos undefinedenull
Lukasz Wiktor
@LukaszWiktor Correto, a pergunta pediu indefinido ou nulo.
JHH
88

Forros um mais curtos para ES6 +

Filtrar todos os valores Falsas ( "", 0, false, null, undefined)

Object.entries(obj).reduce((a,[k,v]) => (v ? (a[k]=v, a) : a), {})

Filtro nulle undefinedvalores:

Object.entries(obj).reduce((a,[k,v]) => (v == null ? a : (a[k]=v, a)), {})

Filtrar SOMENTE null

Object.entries(obj).reduce((a,[k,v]) => (v === null ? a : (a[k]=v, a)), {})

Filtrar SOMENTE undefined

Object.entries(obj).reduce((a,[k,v]) => (v === undefined ? a : (a[k]=v, a)), {})

Soluções Recursivas: Filtros nulleundefined

Para objetos:

const cleanEmpty = obj => Object.entries(obj)
        .map(([k,v])=>[k,v && typeof v === "object" ? cleanEmpty(v) : v])
        .reduce((a,[k,v]) => (v == null ? a : (a[k]=v, a)), {});

Para objetos e matrizes:

const cleanEmpty = obj => {
  if (Array.isArray(obj)) { 
    return obj
        .map(v => (v && typeof v === 'object') ? cleanEmpty(v) : v)
        .filter(v => !(v == null)); 
  } else { 
    return Object.entries(obj)
        .map(([k, v]) => [k, v && typeof v === 'object' ? cleanEmpty(v) : v])
        .reduce((a, [k, v]) => (v == null ? a : (a[k]=v, a)), {});
  } 
}
galinhas
fonte
10
Essa deve ser a única resposta! Cada um desses trechos gerará um novo objeto em que o antigo não será alterado. Isso é preferível! Uma pequena nota, se você apenas usar, v == nullfará check contra undefinede null.
Megajin 26/08/19
as cleanEmptysoluções recursivas retornarão um objeto vazio {}para objetos Date
Emmanuel NK
Um pouco mais de legibilidade nos forros os tornaria incríveis!
zardilior 9/06
39

Se alguém precisa de uma versão recursiva da resposta de Owen (e de Eric), aqui está:

/**
 * Delete all null (or undefined) properties from an object.
 * Set 'recurse' to true if you also want to delete properties in nested objects.
 */
function delete_null_properties(test, recurse) {
    for (var i in test) {
        if (test[i] === null) {
            delete test[i];
        } else if (recurse && typeof test[i] === 'object') {
            delete_null_properties(test[i], recurse);
        }
    }
}
Wumms
fonte
Após o loop começa, você deve verificar que o objeto hasOwnPropertyusandoif(test.hasOwnProperty(i)) { ... }
Augie Gardner
@AugieGardner Estou curioso para saber por que você gostaria de verificar isso - por favor, explique se quiser. (Não seria impedir a verificação das propriedades herdadas?)
Wumms
24

JSON.stringify remove as chaves indefinidas.

removeUndefined = function(json){
  return JSON.parse(JSON.stringify(json))
}
Alexandre Farber
fonte
Isso não funcionou para mim para um objeto profundo, mas a resposta de Wumm acima funcionou.
Suman
1
Se você precisar nullser tratado como undefinedusar a função de substituição, para obter mais informações, consulte esta resposta: stackoverflow.com/questions/286141/…
Hooman Askari
Esteja ciente de que isso não remove nullvalores. Tente: let a = { b: 1, c: 0, d: false, e: null, f: undefined, g: [], h: {} }e depois console.log(removeUndefined(a)). A pergunta era sobre undefinede nullvalores.
1819 Mayid
13

Você provavelmente está procurando a deletepalavra - chave.

var obj = { };
obj.theProperty = 1;
delete obj.theProperty;
yfeldblum
fonte
4
Isto é o que ele está fazendo acima, isso também ainda permanece indefinido no objeto.
Josh Bedo 24/07
10

A solução Lodash mais simples possível para retornar um objeto com os valores nulle undefinedfiltrados.

_.omitBy(obj, _.isNil)

JeffD23
fonte
esta é a solução mais limpa até agora!
Jee Mok
9

Você pode usar uma combinação de JSON.stringifyseu parâmetro substituto e JSON.parsetransformá-lo novamente em um objeto. O uso desse método também significa que a substituição é feita em todas as chaves aninhadas nos objetos aninhados.

Objeto de exemplo

var exampleObject = {
  string: 'value',
  emptyString: '',
  integer: 0,
  nullValue: null,
  array: [1, 2, 3],
  object: {
    string: 'value',
    emptyString: '',
    integer: 0,
    nullValue: null,
    array: [1, 2, 3]
  },
  arrayOfObjects: [
    {
      string: 'value',
      emptyString: '',
      integer: 0,
      nullValue: null,
      array: [1, 2, 3]
    },
    {
      string: 'value',
      emptyString: '',
      integer: 0,
      nullValue: null,
      array: [1, 2, 3]
    }
  ]
};

Função Replacer

function replaceUndefinedOrNull(key, value) {
  if (value === null || value === undefined) {
    return undefined;
  }

  return value;
}

Limpe o objeto

exampleObject = JSON.stringify(exampleObject, replaceUndefinedOrNull);
exampleObject = JSON.parse(exampleObject);

Exemplo de CodePen

Alex Mueller
fonte
6

Usando Ramda # pickBy você vai remover todos null, undefinede falsevalores:

const obj = {a:1, b: undefined, c: null, d: 1}
R.pickBy(R.identity, obj)

Como @manroe apontou, para manter os falsevalores use isNil():

const obj = {a:1, b: undefined, c: null, d: 1, e: false}
R.pickBy(v => !R.isNil(v), obj)
Amio.io
fonte
1
(v) => !R.isNil(v)é provavelmente uma escolha melhor para a pergunta do OP, uma vez que falseou outros valores Falsas também seria rejeitado porR.identity
manroe
6

Abordagem funcional e imutável, sem .filtere sem a criação de mais objetos do que o necessário

Object.keys(obj).reduce((acc, key) => (obj[key] === undefined ? acc : {...acc, [key]: obj[key]}), {})
peralmq
fonte
Resposta muito concisa. Para adicionar também a verificação nula, basta substituir obj[key] === undefinedporobj[key] === undefined || obj[key] === null
user3658510 14/08/19
uma ligeira variação da abordagem acima: você também pode condicionalmente espalhar na propriedade obj truthy como assimconst omitFalsy = obj => Object.keys(obj).reduce((acc, key) => ({ ...acc, ...(obj[key] && { [key]: obj[key] }) }), {});
Kevin K.
6

Você pode fazer uma remoção recursiva em uma linha usando o argumento substituto de json.stringify

const removeEmptyValues = obj => (
  JSON.parse(JSON.stringify(obj, (k,v) => v ?? undefined))
)

Uso:

removeEmptyValues({a:{x:1,y:null,z:undefined}}) // Returns {a:{x:1}}

Como mencionado no comentário de Emmanuel, essa técnica funcionou apenas se sua estrutura de dados contiver apenas tipos de dados que podem ser colocados no formato JSON (cadeias, números, listas, etc.).

(Esta resposta foi atualizada para usar o novo operador Nullish Coalescing dependendo das necessidades de apoio navegador que você pode querer usar esta função em vez disso:. (k,v) => v!=null ? v : undefined)

Scotty Jamison
fonte
1
isso irá converter objetos de data para cordas, convertidos NaNpara nullque não são removidos.
Emmanuel NK
5

você pode fazer mais curto com !condição

var r = {a: null, b: undefined, c:1};
for(var k in r)
   if(!r[k]) delete r[k];

Lembre-se de usar: como @semicolor anuncia nos comentários: Isso também excluiria propriedades se o valor fosse uma sequência vazia, falsa ou zero

nguyên
fonte
11
Isso também excluiria propriedades se o valor for uma sequência vazia, falsa ou zero.
Ponto
3
Era exatamente o que eu estava procurando para remover campos indesejados de uma solicitação JSON. Obrigado!
Phrozen
Use em [null, undefined].includes(r[k])vez de !r[k].
Selmanamet 13/1018
5

Solução pura ES6 mais curta, converta-a em uma matriz, use a função de filtro e converta-a novamente em um objeto. Também seria fácil fazer uma função ...

Btw. com isso, .length > 0verifico se existe uma string / matriz vazia, para remover as chaves vazias.

const MY_OBJECT = { f: 'te', a: [] }

Object.keys(MY_OBJECT)
 .filter(f => !!MY_OBJECT[f] && MY_OBJECT[f].length > 0)
 .reduce((r, i) => { r[i] = MY_OBJECT[i]; return r; }, {});

JS BIN https://jsbin.com/kugoyinora/edit?js,console

Michael J. Zoidl
fonte
1
Solução funcional agradável
puiu
Eu gosto disso! Mas acho que para remover tudo nulle undefinedseria mais simples usar apenas MY_OBJECT[f] != null. Sua solução atual remove tudo, mas não vazias cordas / listas e gera um erro quando os valores sãonull
Rotareti
Certo, você também pode usar / encadear múltiplos filter's, seria mais legível.
Michael J. Zoidl
Se você generalizar este ligeiramente Eu acho que você chegar perto do que de loadash omitnão, você precisa verificar obj existe antes de chamar Object.keys:const omit = (obj, filter) => obj && Object.keys(obj).filter(key => !filter(obj[key])).reduce((acc,key) => {acc[key] = obj[key]; return acc}, {});
icc97
Bom, mas qualquer valor inteiro será removido com essa abordagem.
Ghis 13/12/19
4

Se você deseja 4 linhas de uma solução ES7 pura:

const clean = e => e instanceof Object ? Object.entries(e).reduce((o, [k, v]) => {
  if (typeof v === 'boolean' || v) o[k] = clean(v);
  return o;
}, e instanceof Array ? [] : {}) : e;

Ou se você preferir uma versão mais legível:

function filterEmpty(obj, [key, val]) {
  if (typeof val === 'boolean' || val) {
    obj[key] = clean(val)
  };

  return obj;
}

function clean(entry) {
  if (entry instanceof Object) {
    const type = entry instanceof Array ? [] : {};
    const entries = Object.entries(entry);

    return entries.reduce(filterEmpty, type);
  }

  return entry;
}

Isso preservará os valores booleanos e também limpará as matrizes. Ele também preserva o objeto original retornando uma cópia limpa.

DaniOcean
fonte
4

Eu tenho o mesmo cenário no meu projeto e consegui usando o método a seguir.

Funciona com todos os tipos de dados, poucos mencionados acima não funcionam com data e matrizes vazias.

removeEmptyKeysFromObject.js

removeEmptyKeysFromObject(obj) {
   Object.keys(obj).forEach(key => {
  if (Object.prototype.toString.call(obj[key]) === '[object Date]' && (obj[key].toString().length === 0 || obj[key].toString() === 'Invalid Date')) {
    delete obj[key];
  } else if (obj[key] && typeof obj[key] === 'object') {
    this.removeEmptyKeysFromObject(obj[key]);
  } else if (obj[key] == null || obj[key] === '') {
    delete obj[key];
  }

  if (obj[key]
    && typeof obj[key] === 'object'
    && Object.keys(obj[key]).length === 0
    && Object.prototype.toString.call(obj[key]) !== '[object Date]') {
    delete obj[key];
  }
});
  return obj;
}

passar qualquer objeto para esta função removeEmptyKeysFromObject ()

bharath muppa
fonte
4

Para uma pesquisa profunda, usei o seguinte código, talvez seja útil para qualquer pessoa que esteja olhando para essa pergunta (não é utilizável para dependências cíclicas):

function removeEmptyValues(obj) {
        for (var propName in obj) {
            if (!obj[propName] || obj[propName].length === 0) {
                delete obj[propName];
            } else if (typeof obj[propName] === 'object') {
                removeEmptyValues(obj[propName]);
            }
        }
        return obj;
    }
sam
fonte
3

Se você não quiser fazer a mutação no local, mas retornar um clone com o nulo / indefinido removido, poderá usar a função de redução do ES6.

// Helper to remove undefined or null properties from an object
function removeEmpty(obj) {
  // Protect against null/undefined object passed in
  return Object.keys(obj || {}).reduce((x, k) => {
    // Check for null or undefined
    if (obj[k] != null) {
      x[k] = obj[k];
    }
    return x;
  }, {});
}
bsyk
fonte
3

Em vez de excluir a propriedade, você também pode criar um novo objeto com as chaves que não são nulas.

const removeEmpty = (obj) => {
  return Object.keys(obj).filter(key => obj[key]).reduce(
    (newObj, key) => {
      newObj[key] = obj[key]
      return newObj
    }, {}
  )
}
Jin Zhao
fonte
3

Para piggypack na resposta de Ben sobre como resolver esse problema usando o lodash _.pickBy, você também pode resolvê-lo na biblioteca irmã: Underscore.js 's _.pick.

var obj = {name: 'John', age: null};

var compacted = _.pick(obj, function(value) {
  return value !== null && value !== undefined;
});

Veja: Exemplo JSFiddle

Alex Johnson
fonte
1
Isso retorna array vazio, você também mudou o nome do obj ao objeto
Stephen DuMont
Obrigado Stephen! Que tal agora? Atualizei minha resposta para incluir um link do JSFiddle.
Alex Johnson
tente usar _.omit (obj, _.isEmpty); isso é mais conceitualmente puro e incluirá uma sequência vazia.
Stephen DuMont
3

um auxiliar de redução pode fazer o truque (sem verificação de tipo) -

const cleanObj = Object.entries(objToClean).reduce((acc, [key, value]) => {
      if (value) {
        acc[key] = value;
      }
      return acc;
    }, {});
Yinon
fonte
2

Se alguém precisar remover undefinedvalores de um objeto com pesquisa profunda usando lodash, aqui está o código que estou usando. É bastante simples modificá-lo para remover todos os valores vazios ( null/ undefined).

function omitUndefinedDeep(obj) {
  return _.reduce(obj, function(result, value, key) {
    if (_.isObject(value)) {
      result[key] = omitUndefinedDeep(value);
    }
    else if (!_.isUndefined(value)) {
      result[key] = value;
    }
    return result;
  }, {});
}
Łukasz Jagodziński
fonte
1

Com o Lodash:

_.omitBy({a: 1, b: null}, (v) => !v)
Dana Woodman
fonte
1

Se você usa eslint e deseja evitar tropeçar na regra no-param-reassign, é possível usar Object.assign em conjunto com .reduce e um nome de propriedade calculado para uma solução ES6 bastante elegante:

const queryParams = { a: 'a', b: 'b', c: 'c', d: undefined, e: null, f: '', g: 0 };
const cleanParams = Object.keys(queryParams) 
  .filter(key => queryParams[key] != null)
  .reduce((acc, key) => Object.assign(acc, { [key]: queryParams[key] }), {});
// { a: 'a', b: 'b', c: 'c', f: '', g: 0 }
dpmott
fonte
1

Aqui está uma maneira funcional de remover nullsde um Objeto usando o ES6 sem alterar o objeto usando apenas reduce:

const stripNulls = (obj) => {
  return Object.keys(obj).reduce((acc, current) => {
    if (obj[current] !== null) {
      return { ...acc, [current]: obj[current] }
    }
    return acc
  }, {})
}
Felippe Nardi
fonte
Troll comment Duas coisas em relação a esse padrão funcional: dentro da stripNullsfunção, ele usa uma referência de fora do escopo da função acumulador; e também mistura as preocupações filtrando a função acumulador. Eg (por exemplo Object.entries(o).filter(([k,v]) => v !== null).reduce((o, [k, v]) => {o[k] = v; return o;}, {});) Sim, ele
21818 Jason Cust
1

Você também pode usar a ...sintaxe de propagação usando forEachalgo como isto:

let obj = { a: 1, b: "b", c: undefined, d: null };
let cleanObj = {};

Object.keys(obj).forEach(val => {
  const newVal = obj[val];
  cleanObj = newVal ? { ...cleanObj, [val]: newVal } : cleanObj;
});

console.info(cleanObj);
Hardik Pithva
fonte
1

Objeto limpo no lugar

// General cleanObj function
const cleanObj = (valsToRemoveArr, obj) => {
   Object.keys(obj).forEach( (key) =>
      if (valsToRemoveArr.includes(obj[key])){
         delete obj[key]
      }
   })
}

cleanObj([undefined, null], obj)

Função pura

const getObjWithoutVals = (dontReturnValsArr, obj) => {
    const cleanObj = {}
    Object.entries(obj).forEach( ([key, val]) => {
        if(!dontReturnValsArr.includes(val)){
            cleanObj[key]= val
        } 
    })
    return cleanObj
}

//To get a new object without `null` or `undefined` run: 
const nonEmptyObj = getObjWithoutVals([undefined, null], obj)
Ben Carp
fonte
Este é um bom, possivelmente one-liner, solução
Rekam
1

Podemos usar JSON.stringify e JSON.parse para remover atributos em branco de um objeto.

jsObject = JSON.parse(JSON.stringify(jsObject), (key, value) => {
               if (value == null || value == '' || value == [] || value == {})
                   return undefined;
               return value;
           });
Vardaman PK
fonte
Esse truque é realmente válido, desde que você garanta que o Obj seja serializável em JSON. E funciona profundamente também.
Polv 5/01
Comparação inválida de array e objeto ( {} != {}e [] != []), mas de outra forma a abordagem é válida
Aivaras
1

Aqui está uma função recursiva abrangente (originalmente baseada na de @chickens) que:

  • remova recursivamente o que você diz defaults=[undefined, null, '', NaN]
  • Manuseie corretamente objetos regulares, matrizes e objetos Date
const cleanEmpty = function(obj, defaults = [undefined, null, NaN, '']) {
  if (!defaults.length) return obj
  if (defaults.includes(obj)) return

  if (Array.isArray(obj))
    return obj
      .map(v => v && typeof v === 'object' ? cleanEmpty(v, defaults) : v)
      .filter(v => !defaults.includes(v))

  return Object.entries(obj).length 
    ? Object.entries(obj)
        .map(([k, v]) => ([k, v && typeof v === 'object' ? cleanEmpty(v, defaults) : v]))
        .reduce((a, [k, v]) => (defaults.includes(v) ? a : { ...a, [k]: v}), {}) 
    : obj
}

USO:

// based off the recursive cleanEmpty function by @chickens. 
// This one can also handle Date objects correctly 
// and has a defaults list for values you want stripped.

const cleanEmpty = function(obj, defaults = [undefined, null, NaN, '']) {
  if (!defaults.length) return obj
  if (defaults.includes(obj)) return

  if (Array.isArray(obj))
    return obj
      .map(v => v && typeof v === 'object' ? cleanEmpty(v, defaults) : v)
      .filter(v => !defaults.includes(v))

  return Object.entries(obj).length 
    ? Object.entries(obj)
        .map(([k, v]) => ([k, v && typeof v === 'object' ? cleanEmpty(v, defaults) : v]))
        .reduce((a, [k, v]) => (defaults.includes(v) ? a : { ...a, [k]: v}), {}) 
    : obj
}


// testing

console.log('testing: undefined \n', cleanEmpty(undefined))
console.log('testing: null \n',cleanEmpty(null))
console.log('testing: NaN \n',cleanEmpty(NaN))
console.log('testing: empty string \n',cleanEmpty(''))
console.log('testing: empty array \n',cleanEmpty([]))
console.log('testing: date object \n',cleanEmpty(new Date(1589339052 * 1000)))
console.log('testing: nested empty arr \n',cleanEmpty({ 1: { 2 :null, 3: [] }}))
console.log('testing: comprehensive obj \n', cleanEmpty({
  a: 5,
  b: 0,
  c: undefined,
  d: {
    e: null,
    f: [{
      a: undefined,
      b: new Date(),
      c: ''
    }]
  },
  g: NaN,
  h: null
}))
console.log('testing: different defaults \n', cleanEmpty({
  a: 5,
  b: 0,
  c: undefined,
  d: {
    e: null,
    f: [{
      a: undefined,
      b: '',
      c: new Date()
    }]
  },
  g: [0, 1, 2, 3, 4],
  h: '',
}, [undefined, null]))

Emmanuel NK
fonte
0

Se você preferir a abordagem pura / funcional

const stripUndef = obj => 
  Object.keys(obj)
   .reduce((p, c) => ({ ...p, ...(x[c] === undefined ? { } : { [c]: x[c] })}), {});
Peter Aron Zentai
fonte