Comment supprimer tous les attributs qui sont undefinedou nulldans un objet JavaScript?
(La question est similaire à celle-ci pour les tableaux)
Comment supprimer tous les attributs qui sont undefinedou nulldans un objet JavaScript?
(La question est similaire à celle-ci pour les tableaux)
Réponses:
Vous pouvez parcourir l'objet en boucle:
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 vous ne souhaitez pas que cette suppression de propriété exécute la chaîne proptype de l'objet, vous pouvez également:
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];
}
}
}
Quelques notes sur null vs indéfini:
test.test1 === null; // true
test.test1 == null; // true
test.notaprop === null; // false
test.notaprop == null; // true
test.notaprop === undefined; // true
test.notaprop == undefined; // true
Utilisation de certains ES6 / ES2015 :
1) Une simple doublure pour retirer les articles en ligne sans affectation:
Object.keys(myObj).forEach((key) => (myObj[key] == null) && delete myObj[key]);
2) Cet exemple a été supprimé ...
3) Premier exemple écrit en fonction:
const removeEmpty = obj => {
Object.keys(obj).forEach(key => obj[key] == null && delete obj[key]);
};
4) Cette fonction utilise également la récursivité pour supprimer les éléments des objets imbriqués:
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) Ceci est similaire au 4), mais au lieu de muter directement l'objet source, il renvoie un nouvel objet.
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) Une approche fonctionnelle de 4b) basée sur la réponse de @ MichaelJ.Zoidl en utilisant filter()et reduce(). Celui-ci renvoie également un nouvel objet:
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) Identique à 4) mais avec 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) Une autre
version fonctionnelle qui utilise la récursivité et renvoie un nouvel objet avec 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) Identique à 4) mais en clair 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 an object, donc oet kest évident. Mais je suppose que c'est une question de goût.
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 vous utilisez lodash ou underscore.js, voici une solution simple:
var obj = {name: 'John', age: null};
var compacted = _.pickBy(obj);
Cela ne fonctionnera qu'avec lodash 4, pre lodash 4 ou underscore.js, use _.pick(obj, _.identity);
_.omit(obj, _.isUndefined)c'est mieux.
_.isUndefinedn'omet pas de valeurs nulles, utilisez _.omitBy(obj, _.isNil)pour omettre les deux undefinedetnull
Doublures les plus courtes pour ES6 +
Filtrer toutes les valeurs falsy ( "", 0, false, null, undefined)
Object.entries(obj).reduce((a,[k,v]) => (v ? (a[k]=v, a) : a), {})
Filtre nullet undefinedvaleurs:
Object.entries(obj).reduce((a,[k,v]) => (v == null ? a : (a[k]=v, a)), {})
Filtre UNIQUEMENT null
Object.entries(obj).reduce((a,[k,v]) => (v === null ? a : (a[k]=v, a)), {})
Filtre UNIQUEMENT undefined
Object.entries(obj).reduce((a,[k,v]) => (v === undefined ? a : (a[k]=v, a)), {})
Solutions récursives: filtresnull etundefined
Pour les objets:
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)), {});
Pour les objets et les tableaux:
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 == nullvous vérifierez contre undefinedet null.
cleanEmptysolutions récursives renverront un objet vide {}pour les objets Date
Si quelqu'un a besoin d'une version récursive de la réponse d'Owen (et d'Eric), la voici:
/**
* 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);
}
}
}
hasOwnPropertyutiliseif(test.hasOwnProperty(i)) { ... }
JSON.stringify supprime les clés non définies.
removeUndefined = function(json){
return JSON.parse(JSON.stringify(json))
}
nullêtre traité comme undefinedutilisant la fonction de remplacement, pour plus d'informations, reportez-vous à cette réponse: stackoverflow.com/questions/286141/…
nullvaleurs. Essayez: let a = { b: 1, c: 0, d: false, e: null, f: undefined, g: [], h: {} }et ensuite console.log(removeUndefined(a)). Question était sur le point undefinedet les nullvaleurs.
Vous pouvez utiliser une combinaison de JSON.stringify, son paramètre de remplacement, et JSON.parsele transformer en objet. L'utilisation de cette méthode signifie également que le remplacement est effectué pour toutes les clés imbriquées dans les objets imbriqués.
Exemple d'objet
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]
}
]
};
Fonction de remplacement
function replaceUndefinedOrNull(key, value) {
if (value === null || value === undefined) {
return undefined;
}
return value;
}
Nettoyez l'objet
exampleObject = JSON.stringify(exampleObject, replaceUndefinedOrNull);
exampleObject = JSON.parse(exampleObject);
En utilisant Ramda # pickBy vous enlèverez tous null, undefinedet les falsevaleurs:
const obj = {a:1, b: undefined, c: null, d: 1}
R.pickBy(R.identity, obj)
Comme l'a souligné @manroe, pour conserver les falsevaleurs, utilisez isNil():
const obj = {a:1, b: undefined, c: null, d: 1, e: false}
R.pickBy(v => !R.isNil(v), obj)
(v) => !R.isNil(v)est probablement un meilleur choix pour la question de OP, étant donné que falseou d'autres valeurs de fausseté seraient également rejetées parR.identity
Approche fonctionnelle et immuable, sans .filteret sans créer plus d'objets que nécessaire
Object.keys(obj).reduce((acc, key) => (obj[key] === undefined ? acc : {...acc, [key]: obj[key]}), {})
obj[key] === undefinedparobj[key] === undefined || obj[key] === null
const omitFalsy = obj => Object.keys(obj).reduce((acc, key) => ({ ...acc, ...(obj[key] && { [key]: obj[key] }) }), {});
Vous pouvez effectuer une suppression récursive sur une seule ligne à l'aide de l'argument de remplacement de json.stringify
const removeEmptyValues = obj => (
JSON.parse(JSON.stringify(obj, (k,v) => v ?? undefined))
)
Usage:
removeEmptyValues({a:{x:1,y:null,z:undefined}}) // Returns {a:{x:1}}
Comme mentionné dans le commentaire d'Emmanuel, cette technique ne fonctionnait que si votre structure de données ne contient que des types de données pouvant être mis au format JSON (chaînes, nombres, listes, etc.).
(Cette réponse a été mis à jour pour utiliser le nouvel opérateur Nullish Coalescing en fonction des besoins de soutien du navigateur que vous pouvez utiliser cette fonction au lieu. (k,v) => v!=null ? v : undefined)
NaNà nullqui ne sont pas supprimés.
vous pouvez faire plus court avec !condition
var r = {a: null, b: undefined, c:1};
for(var k in r)
if(!r[k]) delete r[k];
Rappelez-vous à l'usage: comme @semicolor annonce dans les commentaires: Cela supprimerait également les propriétés si la valeur est une chaîne vide, fausse ou nulle
[null, undefined].includes(r[k])au lieu de !r[k].
Solution ES6 pure plus courte, convertissez-la en tableau, utilisez la fonction de filtre et convertissez-la en objet. Serait aussi facile de faire une fonction ...
Btw. avec cela, .length > 0je vérifie s'il y a une chaîne / un tableau vide, donc il supprimera les clés vides.
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; }, {});
nullet undefinedqu'il serait plus simple de simplement l'utiliser MY_OBJECT[f] != null. Votre solution actuelle supprime tout sauf les chaînes / listes non vides et génère une erreur lorsque les valeurs sontnull
filter, serait plus lisible.
omit, vous devez vérifier que obj existe avant d'appeler 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 vous voulez 4 lignes d'une solution ES7 pure:
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 si vous préférez une version plus lisible:
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;
}
Cela préservera les valeurs booléennes et nettoiera également les tableaux. Il préserve également l'objet d'origine en renvoyant une copie nettoyée.
J'ai le même scénario dans mon projet et réalisé en utilisant la méthode suivante.
Il fonctionne avec tous les types de données, quelques-uns mentionnés ci-dessus ne fonctionnent pas avec la date et les tableaux vides.
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;
}
passer n'importe quel objet à cette fonction removeEmptyKeysFromObject ()
Pour une recherche approfondie, j'ai utilisé le code suivant, peut-être qu'il sera utile pour quiconque regarde cette question (il n'est pas utilisable pour les dépendances cycliques):
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 vous ne voulez pas muter sur place, mais renvoyez un clone avec la valeur null / undefined supprimée, vous pouvez utiliser la fonction de réduction 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;
}, {});
}
Pour piggypack sur la réponse de Ben sur la façon de résoudre ce problème à l' aide de lodash _.pickBy, vous pouvez également résoudre ce problème dans la bibliothèque sœur: Underscore.js de _.pick.
var obj = {name: 'John', age: null};
var compacted = _.pick(obj, function(value) {
return value !== null && value !== undefined;
});
Voir: Exemple JSFiddle
Si quelqu'un a besoin de supprimer des undefinedvaleurs d'un objet avec une recherche approfondie en utilisant lodashalors voici le code que j'utilise. Il est assez simple de le modifier pour supprimer toutes les valeurs vides ( 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;
}, {});
}
Avec Lodash:
_.omitBy({a: 1, b: null}, (v) => !v)
Si vous utilisez eslint et que vous souhaitez éviter de déclencher la règle no-param-reusign, vous pouvez utiliser Object.assign en conjonction avec .reduce et un nom de propriété calculé pour une solution ES6 assez élégante:
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 }
Voici un moyen fonctionnel de supprimer nullsd'un objet à l'aide d'ES6 sans muter l'objet en utilisant uniquement reduce:
const stripNulls = (obj) => {
return Object.keys(obj).reduce((acc, current) => {
if (obj[current] !== null) {
return { ...acc, [current]: obj[current] }
}
return acc
}, {})
}
stripNullsfonction, il utilise une référence extérieure à la portée de la fonction accumulateur; et il mélange également les préoccupations en filtrant au sein de la fonction d'accumulateur. Eg (par exemple Object.entries(o).filter(([k,v]) => v !== null).reduce((o, [k, v]) => {o[k] = v; return o;}, {});) Oui, il fera une boucle sur les éléments filtrés deux fois, mais la perte de performance réalisée y est négligeable.
Vous pouvez également utiliser la ...syntaxe étendue en utilisant forEachquelque chose comme ceci:
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)
Nous pouvons utiliser JSON.stringify et JSON.parse pour supprimer les attributs vides d'un objet.
jsObject = JSON.parse(JSON.stringify(jsObject), (key, value) => {
if (value == null || value == '' || value == [] || value == {})
return undefined;
return value;
});
{} != {}et [] != []), mais sinon l'approche est valide
Voici une fonction récursive complète (basée à l'origine sur celle de @chickens) qui:
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
}
USAGE:
// 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 vous préférez l'approche pure / fonctionnelle
const stripUndef = obj =>
Object.keys(obj)
.reduce((p, c) => ({ ...p, ...(x[c] === undefined ? { } : { [c]: x[c] })}), {});