Como removo todos os atributos que estão undefinedou estão nullem um objeto JavaScript?
(A pergunta é semelhante a esta para matrizes)
Como removo todos os atributos que estão undefinedou estão nullem um objeto JavaScript?
(A pergunta é semelhante a esta para matrizes)
Respostas:
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
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]);
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]);
};
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
});
};
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.
{}
);
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]
});
};
keysde um object, portanto, oe ké óbvio. Mas acho que é uma questão de gosto.
Object.keys(myObj).forEach(function (key) {(myObj[key] == null) && delete myObj[key]});
Object.entries(myObj).reduce((acc, [key, val]) => { if (val) acc[key] = val; return acc; }, {})
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);
_.omit(obj, _.isUndefined)é melhor.
_.isUndefinednão omite nulos, use _.omitBy(obj, _.isNil)para omitir ambos undefinedenull
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)), {});
}
}
v == nullfará check contra undefinede null.
cleanEmptysoluções recursivas retornarão um objeto vazio {}para objetos Date
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);
}
}
}
hasOwnPropertyusandoif(test.hasOwnProperty(i)) { ... }
JSON.stringify remove as chaves indefinidas.
removeUndefined = function(json){
return JSON.parse(JSON.stringify(json))
}
nullser tratado como undefinedusar a função de substituição, para obter mais informações, consulte esta resposta: stackoverflow.com/questions/286141/…
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.
Você provavelmente está procurando a deletepalavra - chave.
var obj = { };
obj.theProperty = 1;
delete obj.theProperty;
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);
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)
(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
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]}), {})
obj[key] === undefinedporobj[key] === undefined || obj[key] === null
const omitFalsy = obj => Object.keys(obj).reduce((acc, key) => ({ ...acc, ...(obj[key] && { [key]: obj[key] }) }), {});
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)
NaNpara nullque não são removidos.
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
[null, undefined].includes(r[k])vez de !r[k].
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; }, {});
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
filter's, seria mais legível.
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}, {});
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.
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 ()
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;
}
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;
}, {});
}
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
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;
}, {});
}
Com o Lodash:
_.omitBy({a: 1, b: null}, (v) => !v)
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 }
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
}, {})
}
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
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);
// General cleanObj function
const cleanObj = (valsToRemoveArr, obj) => {
Object.keys(obj).forEach( (key) =>
if (valsToRemoveArr.includes(obj[key])){
delete obj[key]
}
})
}
cleanObj([undefined, null], obj)
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)
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;
});
{} != {}e [] != []), mas de outra forma a abordagem é válida
Aqui está uma função recursiva abrangente (originalmente baseada na de @chickens) que:
defaults=[undefined, null, '', NaN]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]))
Se você preferir a abordagem pura / funcional
const stripUndef = obj =>
Object.keys(obj)
.reduce((p, c) => ({ ...p, ...(x[c] === undefined ? { } : { [c]: x[c] })}), {});