¿Cómo elimino todos los atributos que están undefinedo nullen un objeto JavaScript?
(La pregunta es similar a esta para las matrices)
¿Cómo elimino todos los atributos que están undefinedo nullen un objeto JavaScript?
(La pregunta es similar a esta para las matrices)
Respuestas:
Puede recorrer el 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);
Si le preocupa que esta eliminación de propiedad no ejecute la cadena de tipo de objeto, también puede:
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];
}
}
}
Algunas 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 algunos ES6 / ES2015 :
1) Una línea simple para eliminar los elementos en línea sin asignación:
Object.keys(myObj).forEach((key) => (myObj[key] == null) && delete myObj[key]);
2) Este ejemplo fue eliminado ...
3) Primer ejemplo escrito como una función:
const removeEmpty = obj => {
Object.keys(obj).forEach(key => obj[key] == null && delete obj[key]);
};
4) Esta función también utiliza la recursión para eliminar elementos de objetos anidados:
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) Esto es similar a 4), pero en lugar de mutar el objeto fuente directamente, devuelve un nuevo 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) Un enfoque funcional para 4b) basado en la respuesta de @ MichaelJ.Zoidl usando filter()y reduce(). Este también devuelve un nuevo 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) Igual que 4) pero con 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) Otra
versión funcional que utiliza la recursión y devuelve un nuevo objeto con 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) Igual que 4) pero en ES5 simple :
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 una object, por lo que oy kson evidentes. Pero supongo que es cuestión de gustos.
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; }, {})
Si está usando lodash o underscore.js, aquí hay una solución simple:
var obj = {name: 'John', age: null};
var compacted = _.pickBy(obj);
Esto solo funcionará con lodash 4, pre lodash 4 o underscore.js, use _.pick(obj, _.identity);
_.omit(obj, _.isUndefined)es mejor.
_.isUndefinedno omite nulos, se usa _.omitBy(obj, _.isNil)para omitir ambos undefinedynull
Los revestimientos más cortos para ES6 +
Filtrar todos los valores Falsy ( "", 0, false, null, undefined)
Object.entries(obj).reduce((a,[k,v]) => (v ? (a[k]=v, a) : a), {})
Filtro nully undefinedvalores:
Object.entries(obj).reduce((a,[k,v]) => (v == null ? a : (a[k]=v, a)), {})
Filtro SOLO null
Object.entries(obj).reduce((a,[k,v]) => (v === null ? a : (a[k]=v, a)), {})
Filtro SOLO undefined
Object.entries(obj).reduce((a,[k,v]) => (v === undefined ? a : (a[k]=v, a)), {})
Soluciones recursivas: filtros nullyundefined
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 y matrices:
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 == nullusas verificará contra undefinedy null.
cleanEmptysoluciones recursivas devolverán un objeto vacío {}para objetos Date
Si alguien necesita una versión recursiva de la respuesta de Owen (y Eric), aquí 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 elimina las claves indefinidas.
removeUndefined = function(json){
return JSON.parse(JSON.stringify(json))
}
nullser tratado como undefinedusar la función de reemplazo, para obtener más información, consulte esta respuesta: stackoverflow.com/questions/286141/…
nullvalores. Prueba: let a = { b: 1, c: 0, d: false, e: null, f: undefined, g: [], h: {} }y luego console.log(removeUndefined(a)). La pregunta era sobre undefinedy nullvalores.
Puede usar una combinación de JSON.stringify, su parámetro de reemplazo yJSON.parse convertirlo nuevamente en un objeto. El uso de este método también significa que el reemplazo se realiza a todas las claves anidadas dentro de los objetos anidados.
Objeto de ejemplo
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]
}
]
};
Función de reemplazo
function replaceUndefinedOrNull(key, value) {
if (value === null || value === undefined) {
return undefined;
}
return value;
}
Limpiar el objeto
exampleObject = JSON.stringify(exampleObject, replaceUndefinedOrNull);
exampleObject = JSON.parse(exampleObject);
Usando ramda # pickBy eliminará todo null, undefinedy los falsevalores:
const obj = {a:1, b: undefined, c: null, d: 1}
R.pickBy(R.identity, obj)
Como señaló @manroe, para mantener los 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)es probablemente una mejor opción para la pregunta de OP, dado que falseu otros valores falsos también serían rechazados porR.identity
Enfoque funcional e inmutable, sin .filtery sin crear más objetos de los necesarios
Object.keys(obj).reduce((acc, key) => (obj[key] === undefined ? acc : {...acc, [key]: obj[key]}), {})
obj[key] === undefinedaobj[key] === undefined || obj[key] === null
const omitFalsy = obj => Object.keys(obj).reduce((acc, key) => ({ ...acc, ...(obj[key] && { [key]: obj[key] }) }), {});
Puede hacer una eliminación recursiva en una línea usando el argumento de reemplazo 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 se menciona en el comentario de Emmanuel, esta técnica solo funciona si su estructura de datos contiene solo tipos de datos que se pueden poner en formato JSON (cadenas, números, listas, etc.).
(Esta respuesta ha sido actualizado para utilizar el nuevo operador Nullish coalescente en función de las necesidades de apoyo del navegador es posible que desee utilizar esta función en lugar:. (k,v) => v!=null ? v : undefined)
NaNa las nullque no se eliminan.
puedes hacerlo más corto con !condición
var r = {a: null, b: undefined, c:1};
for(var k in r)
if(!r[k]) delete r[k];
Recuerde en uso: como @semicolor anuncia en los comentarios: Esto también eliminaría propiedades si el valor es una cadena vacía, falsa o cero
[null, undefined].includes(r[k])lugar de !r[k].
Solución pura ES6 más corta, conviértala en una matriz, use la función de filtro y vuelva a convertirla en un objeto También sería fácil hacer una función ...
Por cierto. con esto .length > 0verifico si hay una cadena / matriz vacía, por lo que eliminará las claves vacías.
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; }, {});
nully undefinedsería más fácil de usar MY_OBJECT[f] != null. Su solución actual elimina todo menos las cadenas / listas no vacías y arroja un error cuando los valores sonnull
filter, sería más legible.
omit, debes verificar que obj existe antes de llamar Object.keys:const omit = (obj, filter) => obj && Object.keys(obj).filter(key => !filter(obj[key])).reduce((acc,key) => {acc[key] = obj[key]; return acc}, {});
Si desea 4 líneas de una solución 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;
O si prefieres una versión más legible:
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;
}
Esto preservará los valores booleanos y también limpiará las matrices. También conserva el objeto original al devolver una copia limpia.
Tengo el mismo escenario en mi proyecto y lo logré usando el siguiente método.
Funciona con todos los tipos de datos, algunos mencionados anteriormente no funcionan con fecha y matrices vacías.
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;
}
pasar cualquier objeto a esta función removeEmptyKeysFromObject ()
Para una búsqueda profunda utilicé el siguiente código, tal vez sea útil para cualquiera que esté mirando esta pregunta (no es utilizable para dependencias 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;
}
Si no desea mutar en su lugar, pero devuelve un clon con el valor nulo / indefinido eliminado, puede usar la función de reducción 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 aprovechar la respuesta de Ben sobre cómo resolver este problema usando lodash _.pickBy, también puede resolver este problema en la biblioteca hermana: Underscore.js 's _.pick.
var obj = {name: 'John', age: null};
var compacted = _.pick(obj, function(value) {
return value !== null && value !== undefined;
});
Ver: Ejemplo de JSFiddle
Si alguien necesita eliminar undefinedvalores de un objeto con una búsqueda profunda, lodashentonces aquí está el código que estoy usando. Es bastante simple modificarlo para eliminar todos los valores vacíos ( 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;
}, {});
}
Con Lodash:
_.omitBy({a: 1, b: null}, (v) => !v)
Si usa eslint y desea evitar la desconexión de la regla de no reasignar parámetros, puede usar Object.assign junto con .reduce y un nombre de propiedad calculado para una solución 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 }
Aquí hay una forma funcional de eliminar nullsde un Objeto usando ES6 sin mutar el objeto usando solo reduce:
const stripNulls = (obj) => {
return Object.keys(obj).reduce((acc, current) => {
if (obj[current] !== null) {
return { ...acc, [current]: obj[current] }
}
return acc
}, {})
}
stripNullsfunción utiliza una referencia desde fuera del alcance de la función del acumulador; y también mezcla las preocupaciones al filtrar dentro de la función del acumulador. Eg (p Object.entries(o).filter(([k,v]) => v !== null).reduce((o, [k, v]) => {o[k] = v; return o;}, {});. Ej. ) Sí, recorrerá los elementos filtrados dos veces, pero la pérdida de rendimiento realizada allí es insignificante.
También puede usar la ...sintaxis de propagación usando forEachalgo como esto:
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 y JSON.parse para eliminar atributos en blanco de un objeto.
jsObject = JSON.parse(JSON.stringify(jsObject), (key, value) => {
if (value == null || value == '' || value == [] || value == {})
return undefined;
return value;
});
{} != {}y [] != []), pero por lo demás el enfoque es válido
Aquí hay una función recursiva integral (originalmente basada en la 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]))
Si prefiere el enfoque puro / funcional
const stripUndef = obj =>
Object.keys(obj)
.reduce((p, c) => ({ ...p, ...(x[c] === undefined ? { } : { [c]: x[c] })}), {});