Come rimuovo tutti gli attributi che sono undefinedo nullin un oggetto JavaScript?
(La domanda è simile a questa per gli array)
Come rimuovo tutti gli attributi che sono undefinedo nullin un oggetto JavaScript?
(La domanda è simile a questa per gli array)
Risposte:
Puoi scorrere l'oggetto:
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 sei preoccupato che questa rimozione di proprietà non esegua la catena di proptype dell'oggetto, puoi anche:
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];
}
}
}
Alcune note su null vs undefined:
test.test1 === null; // true
test.test1 == null; // true
test.notaprop === null; // false
test.notaprop == null; // true
test.notaprop === undefined; // true
test.notaprop == undefined; // true
Utilizzando alcuni ES6 / ES2015 :
1) Una semplice fodera per rimuovere gli oggetti in linea senza assegnazione:
Object.keys(myObj).forEach((key) => (myObj[key] == null) && delete myObj[key]);
2) Questo esempio è stato rimosso ...
3) Primo esempio scritto come funzione:
const removeEmpty = obj => {
Object.keys(obj).forEach(key => obj[key] == null && delete obj[key]);
};
4) Questa funzione utilizza ricorsione per eliminare anche elementi da oggetti nidificati:
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) È simile a 4), ma invece di mutare direttamente l'oggetto sorgente, restituisce un nuovo oggetto.
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 approccio funzionale a 4b) basato sulla risposta di @ MichaelJ.Zoidl usando filter()ereduce() . Anche questo restituisce un nuovo oggetto:
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) Come 4) ma 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) Un'altra
versione funzionale che utilizza la ricorsione e restituisce un nuovo oggetto 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) Come 4) ma in ES5 semplice :
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]
});
};
keysda un object, quindi oe ksono ovvi. Ma immagino sia una questione di gusti.
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 stai usando lodash o underscore.js, ecco una soluzione semplice:
var obj = {name: 'John', age: null};
var compacted = _.pickBy(obj);
Funzionerà solo con lodash 4, pre lodash 4 o underscore.js, usare _.pick(obj, _.identity);
_.omit(obj, _.isUndefined)è meglio.
_.isUndefinednon omette i null, usa _.omitBy(obj, _.isNil)per omettere entrambi undefinedenull
Fodere più corte per ES6 +
Filtrare tutti i valori falsy ( "", 0, false, null, undefined)
Object.entries(obj).reduce((a,[k,v]) => (v ? (a[k]=v, a) : a), {})
Filtro nulle undefinedvalori:
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)), {})
Soluzioni ricorsive: filtri nulleundefined
Per gli oggetti:
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)), {});
Per oggetti e matrici:
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 == nullsi verificherà contro undefinede null.
cleanEmptysoluzioni ricorsive restituiranno un oggetto vuoto {}per gli oggetti Date
Se qualcuno ha bisogno di una versione ricorsiva della risposta di Owen (e di Eric), eccola qui:
/**
* 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);
}
}
}
hasOwnPropertyutilizziif(test.hasOwnProperty(i)) { ... }
JSON.stringify rimuove le chiavi indefinite.
removeUndefined = function(json){
return JSON.parse(JSON.stringify(json))
}
nullessere trattato come undefinedutilizzare la funzione di sostituzione, per maggiori informazioni fai riferimento a questa risposta: stackoverflow.com/questions/286141/…
nullvalori. Prova: let a = { b: 1, c: 0, d: false, e: null, f: undefined, g: [], h: {} }e poi console.log(removeUndefined(a)). La domanda riguardava undefinede nullvalori.
Probabilmente stai cercando la deleteparola chiave.
var obj = { };
obj.theProperty = 1;
delete obj.theProperty;
È possibile utilizzare una combinazione di JSON.stringify, il relativo parametro di sostituzione, e JSON.parsetrasformarlo in un oggetto. L'uso di questo metodo significa anche che la sostituzione viene eseguita su tutte le chiavi nidificate all'interno di oggetti nidificati.
Oggetto di esempio
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]
}
]
};
Funzione di sostituzione
function replaceUndefinedOrNull(key, value) {
if (value === null || value === undefined) {
return undefined;
}
return value;
}
Pulisci l'oggetto
exampleObject = JSON.stringify(exampleObject, replaceUndefinedOrNull);
exampleObject = JSON.parse(exampleObject);
Utilizzando Ramda # pickBy verrà rimosso tutto null, undefinede falsevalori:
const obj = {a:1, b: undefined, c: null, d: 1}
R.pickBy(R.identity, obj)
Come ha sottolineato @manroe, per mantenere i falsevalori usare isNil():
const obj = {a:1, b: undefined, c: null, d: 1, e: false}
R.pickBy(v => !R.isNil(v), obj)
(v) => !R.isNil(v)è probabilmente una scelta migliore per la domanda di OP, dato che falseo altri valori falsi verrebbero anch'essi respinti daR.identity
Approccio funzionale e immutabile, senza .filtere senza creare più oggetti del necessario
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] }) }), {});
È possibile eseguire una rimozione ricorsiva in una riga utilizzando l'argomento sostituto di 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}}
Come menzionato nel commento di Emmanuel, questa tecnica ha funzionato solo se la struttura dei dati contiene solo tipi di dati che possono essere inseriti in formato JSON (stringhe, numeri, elenchi, ecc.).
(Questa risposta è stato aggiornato per utilizzare il nuovo operatore di Nullish coalescenza a seconda delle esigenze di supporto del browser si consiglia di utilizzare questa funzione invece:. (k,v) => v!=null ? v : undefined)
NaNa nullcui non vengono rimossi.
puoi fare più corto con le !condizioni
var r = {a: null, b: undefined, c:1};
for(var k in r)
if(!r[k]) delete r[k];
Ricorda in uso: come @semicolor annuncia nei commenti: questo eliminerebbe anche le proprietà se il valore è una stringa vuota, falsa o zero
[null, undefined].includes(r[k])invece di !r[k].
Soluzione pura ES6 più corta, convertirla in un array, utilizzare la funzione filtro e riconvertirla in un oggetto. Sarebbe anche facile fare una funzione ...
Btw. con questo .length > 0controllo se c'è una stringa / matrice vuota, quindi rimuoverà le chiavi vuote.
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 undefinedsarebbe più semplice da usare MY_OBJECT[f] != null. La tua attuale soluzione rimuove tutto tranne le stringhe / liste non vuote e genera un errore quando i valori sononull
filter, sarebbe più leggibile.
omit, devi verificare che obj esista prima di chiamare 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 vuoi 4 linee di una soluzione 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 se preferisci una versione più leggibile:
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;
}
Ciò preserverà i valori booleani e pulirà anche le matrici. Conserva anche l'oggetto originale restituendo una copia pulita.
Ho lo stesso scenario nel mio progetto e realizzato usando il seguente metodo.
Funziona con tutti i tipi di dati, alcuni di cui sopra non funzionano con data e array vuoti.
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;
}
passare qualsiasi oggetto a questa funzione removeEmptyKeysFromObject ()
Per una ricerca approfondita ho usato il seguente codice, forse sarà utile per chiunque guardi questa domanda (non è utilizzabile per dipendenze cicliche):
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 non si desidera eseguire la mutazione sul posto, ma restituire un clone con il valore null / indefinito rimosso, è possibile utilizzare la funzione di riduzione 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;
}, {});
}
Per piggypack sulla risposta di Ben su come risolvere questo problema utilizzando lodash di _.pickBy, è anche possibile risolvere questo problema nella biblioteca sorella: Underscore.js 's _.pick.
var obj = {name: 'John', age: null};
var compacted = _.pick(obj, function(value) {
return value !== null && value !== undefined;
});
Vedi: Esempio JSFiddle
Se qualcuno ha bisogno di rimuovere i undefinedvalori da un oggetto con la ricerca approfondita utilizzando, lodashecco il codice che sto usando. È abbastanza semplice modificarlo per rimuovere tutti i valori vuoti ( 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)
Se usi eslint e vuoi evitare di far scattare la regola no-param-reassign, puoi usare Object.assign insieme a .reduce e un nome di proprietà calcolato per una soluzione ES6 abbastanza 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 }
Ecco un modo funzionale per rimuovere nullsda un oggetto usando ES6 senza mutare l'oggetto usando solo reduce:
const stripNulls = (obj) => {
return Object.keys(obj).reduce((acc, current) => {
if (obj[current] !== null) {
return { ...acc, [current]: obj[current] }
}
return acc
}, {})
}
stripNullsfunzione utilizza un riferimento esterno all'ambito della funzione dell'accumulatore; e mescola anche le preoccupazioni filtrando all'interno della funzione accumulatore. 😝 (es. Object.entries(o).filter(([k,v]) => v !== null).reduce((o, [k, v]) => {o[k] = v; return o;}, {});) Sì, passerà due volte sopra gli oggetti filtrati ma la perdita di perf realizzata è trascurabile.
Puoi anche usare la ...sintassi diffusa usando forEachqualcosa del genere:
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)
Possiamo usare JSON.stringify e JSON.parse per rimuovere attributi vuoti da un oggetto.
jsObject = JSON.parse(JSON.stringify(jsObject), (key, value) => {
if (value == null || value == '' || value == [] || value == {})
return undefined;
return value;
});
{} != {}e [] != []), ma altrimenti l'approccio è valido
Ecco una funzione ricorsiva completa (originariamente basata su quella di @chickens) che:
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 preferisci l'approccio puro / funzionale
const stripUndef = obj =>
Object.keys(obj)
.reduce((p, c) => ({ ...p, ...(x[c] === undefined ? { } : { [c]: x[c] })}), {});