Jak mogę usunąć wszystkie atrybuty, które są undefinedlub nullw obiektu JavaScript?
(Pytanie jest podobne do tego dla tablic)
Jak mogę usunąć wszystkie atrybuty, które są undefinedlub nullw obiektu JavaScript?
(Pytanie jest podobne do tego dla tablic)
Odpowiedzi:
Możesz zapętlić obiekt:
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);
Jeśli obawiasz się, że usunięcie tej właściwości nie uruchamia łańcucha proptype obiektu, możesz również:
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];
}
}
}
Kilka uwag na temat wartości 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
Korzystanie z niektórych ES6 / ES2015 :
1) Prosta jedna linijka do usuwania elementów w linii bez przypisania:
Object.keys(myObj).forEach((key) => (myObj[key] == null) && delete myObj[key]);
2) Ten przykład został usunięty ...
3) Pierwszy przykład napisany jako funkcja:
const removeEmpty = obj => {
Object.keys(obj).forEach(key => obj[key] == null && delete obj[key]);
};
4) Ta funkcja używa rekurencji również do usuwania elementów z zagnieżdżonych obiektów:
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) Jest to podobne do 4), ale zamiast bezpośrednio mutować obiekt źródłowy, zwraca nowy obiekt.
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) Funkcjonalne podejście do 4b) oparte na odpowiedzi @ MichaelJ.Zoidl przy użyciu filter()i reduce(). Ten zwraca również nowy obiekt:
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) Taki sam jak 4), ale z 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) Kolejna funkcjonalna
wersja, która wykorzystuje rekurencję i zwraca nowy obiekt z 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) Taki sam jak 4), ale w zwykłym 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]
});
};
keysz object, więc oi ksą oczywiste. Ale myślę, że to kwestia gustu.
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; }, {})
Jeśli używasz lodash lub underscore.js, oto proste rozwiązanie:
var obj = {name: 'John', age: null};
var compacted = _.pickBy(obj);
Będzie to działać tylko z lodash 4, pre lodash 4 lub underscore.js, użyj _.pick(obj, _.identity);
_.omit(obj, _.isUndefined)jest lepsze.
_.isUndefinednie pomija zer , użyj, _.omitBy(obj, _.isNil)aby pominąć oba undefinedinull
Najkrótsza jedna wkładka do ES6 +
Odfiltrować wszystkie wartości falsy ( "", 0, false, null, undefined)
Object.entries(obj).reduce((a,[k,v]) => (v ? (a[k]=v, a) : a), {})
Filtr nulli undefinedwartości:
Object.entries(obj).reduce((a,[k,v]) => (v == null ? a : (a[k]=v, a)), {})
Filtruj TYLKO null
Object.entries(obj).reduce((a,[k,v]) => (v === null ? a : (a[k]=v, a)), {})
Filtruj TYLKO undefined
Object.entries(obj).reduce((a,[k,v]) => (v === undefined ? a : (a[k]=v, a)), {})
Rozwiązania rekurencyjne: filtry nulliundefined
W przypadku obiektów:
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)), {});
W przypadku obiektów i tablic:
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 == null, sprawdzisz przeciwko undefinedi null.
cleanEmptyrozwiązania recursve zwróci pusty obiekt {}dla obiektów Date
Jeśli ktoś potrzebuje rekurencyjnej wersji odpowiedzi Owena (i Erica), oto:
/**
* 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);
}
}
}
hasOwnPropertyużywaif(test.hasOwnProperty(i)) { ... }
JSON.stringify usuwa niezdefiniowane klucze.
removeUndefined = function(json){
return JSON.parse(JSON.stringify(json))
}
nullbyć traktowany jak undefinedskorzystaj z funkcji zastępowania, więcej informacji znajdziesz w tej odpowiedzi: stackoverflow.com/questions/286141/...
nullwartości. Spróbuj: let a = { b: 1, c: 0, d: false, e: null, f: undefined, g: [], h: {} }a potem console.log(removeUndefined(a)). Pytanie dotyczyło undefinedi nullwartości.
Możesz użyć kombinacji JSON.stringifyparametru zastępującego i JSON.parseprzekształcić go z powrotem w obiekt. Użycie tej metody oznacza również zastąpienie wszystkich zagnieżdżonych kluczy w zagnieżdżonych obiektach.
Przykładowy obiekt
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]
}
]
};
Funkcja zamiennika
function replaceUndefinedOrNull(key, value) {
if (value === null || value === undefined) {
return undefined;
}
return value;
}
Oczyść obiekt
exampleObject = JSON.stringify(exampleObject, replaceUndefinedOrNull);
exampleObject = JSON.parse(exampleObject);
Korzystanie ramda # pickBy można zdjąć null, undefineda falsewartości:
const obj = {a:1, b: undefined, c: null, d: 1}
R.pickBy(R.identity, obj)
Jak wskazał @manroe, aby zachować falsewartości, użyj isNil():
const obj = {a:1, b: undefined, c: null, d: 1, e: false}
R.pickBy(v => !R.isNil(v), obj)
(v) => !R.isNil(v)jest prawdopodobnie lepszym wyborem dla pytania OP, biorąc pod uwagę, że falselub inne wartości fałszowania również zostałyby odrzucone przezR.identity
Funkcjonalne i niezmienne podejście, .filterbez tworzenia i tworzenia większej liczby obiektów niż potrzeba
Object.keys(obj).reduce((acc, key) => (obj[key] === undefined ? acc : {...acc, [key]: obj[key]}), {})
obj[key] === undefinednaobj[key] === undefined || obj[key] === null
const omitFalsy = obj => Object.keys(obj).reduce((acc, key) => ({ ...acc, ...(obj[key] && { [key]: obj[key] }) }), {});
możesz zrobić krócej z !warunkiem
var r = {a: null, b: undefined, c:1};
for(var k in r)
if(!r[k]) delete r[k];
Zapamiętaj w użyciu: jak @semicolor ogłasza w komentarzach: Spowoduje to również usunięcie właściwości, jeśli wartość jest pustym ciągiem, fałszem lub zerem
[null, undefined].includes(r[k])zamiast !r[k].
Krótsze rozwiązanie ES6 pure, przekonwertuj je na tablicę, użyj funkcji filtrowania i przekonwertuj z powrotem na obiekt. Łatwo byłoby również wykonać funkcję ...
Btw. dzięki temu .length > 0sprawdzam, czy jest pusty ciąg / tablica, więc usunie puste klucze.
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; }, {});
nulli undefinedłatwiej byłoby po prostu użyć MY_OBJECT[f] != null. Twoje obecne rozwiązanie usuwa wszystko oprócz niepustych ciągów / list i generuje błąd, gdy wartości sąnull
filter, byłoby bardziej czytelne.
omit, musisz sprawdzić obj istnieje przed wywołaniem Object.keys:const omit = (obj, filter) => obj && Object.keys(obj).filter(key => !filter(obj[key])).reduce((acc,key) => {acc[key] = obj[key]; return acc}, {});
Możesz wykonać rekurencyjne usuwanie w jednym wierszu, używając argumentu zamiennika json.stringify
const removeNullValues = obj => (
JSON.parse(JSON.stringify(obj, (k,v) => v ?? undefined))
)
Stosowanie:
removeNullValues({a:{x:1,y:null,z:undefined}}) // Returns {a:{x:1}}
Jak wspomniano w komentarzu Emmanuela, ta technika działała tylko wtedy, gdy struktura danych zawiera tylko typy danych, które można umieścić w formacie JSON (ciągi, liczby, listy itp.).
(Ta odpowiedź została zaktualizowana do korzystania z nowego operatora Nullish koalescencyjny w zależności od potrzeb klientów przeglądarka może chcesz zamiast korzystać z tej funkcji. (k,v) => v!=null ? v : undefined)
NaNna nullktóre nie zostaną usunięte.
Jeśli chcesz 4 linie czystego rozwiązania ES7:
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;
Lub jeśli wolisz bardziej czytelną wersję:
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;
}
Pozwoli to zachować wartości logiczne i wyczyści również tablice. Zachowuje również oryginalny obiekt, zwracając oczyszczoną kopię.
Mam taki sam scenariusz w moim projekcie i został osiągnięty przy użyciu następującej metody.
Działa ze wszystkimi typami danych, kilka wyżej wymienionych nie działa z datą i pustymi tablicami.
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;
}
przekazuje dowolny obiekt do tej funkcji removeEmptyKeysFromObject ()
Do głębokiego wyszukiwania użyłem następującego kodu, być może będzie przydatny dla każdego, kto patrzy na to pytanie (nie jest to przydatne w przypadku cyklicznych zależności):
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;
}
Jeśli nie chcesz mutować w miejscu, ale zwrócisz klon z usuniętą wartością null / undefined, możesz użyć funkcji redukcji 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;
}, {});
}
Aby piggypack na odpowiedź Bena o tym, jak rozwiązać ten problem przy użyciu lodash użytkownika _.pickBy, można również rozwiązać ten problem w bibliotece Siostro underscore.js „s _.pick.
var obj = {name: 'John', age: null};
var compacted = _.pick(obj, function(value) {
return value !== null && value !== undefined;
});
Zobacz: Przykład JSFiddle
Jeśli ktoś musi usunąć undefinedwartości z obiektu za pomocą głębokiego wyszukiwania, lodashoto kod, którego używam. Bardzo łatwo go zmodyfikować, aby usunąć wszystkie puste wartości ( 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;
}, {});
}
Z Lodash:
_.omitBy({a: 1, b: null}, (v) => !v)
Jeśli używasz eslint i chcesz uniknąć wyłączenia reguły no-param-reassign, możesz użyć Object.assign w połączeniu z .reduce i obliczoną nazwą właściwości dla dość eleganckiego rozwiązania ES6:
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 }
Oto funkcjonalny sposób usunięcia nullsz obiektu za pomocą ES6 bez mutowania obiektu przy użyciu tylko reduce:
const stripNulls = (obj) => {
return Object.keys(obj).reduce((acc, current) => {
if (obj[current] !== null) {
return { ...acc, [current]: obj[current] }
}
return acc
}, {})
}
stripNullsfunkcji wykorzystuje odwołanie spoza zakresu funkcji akumulatora; a także miesza obawy, filtrując w ramach funkcji akumulatora. 😝 (np. Object.entries(o).filter(([k,v]) => v !== null).reduce((o, [k, v]) => {o[k] = v; return o;}, {});) Tak,
Możesz także użyć ...składni spreadu, używając forEachczegoś takiego:
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)
Możemy użyć JSON.stringify i JSON.parse do usunięcia pustych atrybutów z obiektu.
jsObject = JSON.parse(JSON.stringify(jsObject), (key, value) => {
if (value == null || value == '' || value == [] || value == {})
return undefined;
return value;
});
{} != {}i [] != []), ale w innym przypadku poprawne jest podejście
Oto kompleksowa funkcja rekurencyjna (pierwotnie oparta na funkcji @chickens), która:
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
}
STOSOWANIE:
// 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]))
Jeśli wolisz podejście czyste / funkcjonalne
const stripUndef = obj =>
Object.keys(obj)
.reduce((p, c) => ({ ...p, ...(x[c] === undefined ? { } : { [c]: x[c] })}), {});