Як видалити всі атрибути, які є undefinedабо є nullв об’єкті JavaScript?
(Питання схоже на таке для Arrays)
Як видалити всі атрибути, які є undefinedабо є nullв об’єкті JavaScript?
(Питання схоже на таке для Arrays)
Відповіді:
Ви можете провести цикл через об'єкт:
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);
Якщо ви стурбовані тим, що це видалення властивості не працює з ланцюжком прототипів об'єкта, ви також можете:
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];
}
}
}
Кілька приміток про 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
Використання деяких ES6 / ES2015 :
1) Простий однолінійний інструмент для видалення елементів в рядку без призначення:
Object.keys(myObj).forEach((key) => (myObj[key] == null) && delete myObj[key]);
2) Цей приклад видалено ...
3) Перший приклад, записаний як функція:
const removeEmpty = obj => {
Object.keys(obj).forEach(key => obj[key] == null && delete obj[key]);
};
4) Ця функція використовує рекурсію і для видалення елементів з вкладених об'єктів:
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) Це схоже на 4), але замість того, щоб безпосередньо вимкнути вихідний об'єкт, він повертає новий об'єкт.
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) Функціональний підхід до 4b), заснований на відповіді @ MichaelJ.Zoidl з використанням filter()і reduce(). Цей також повертає новий об’єкт:
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) Те саме, що і 4), але з 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) Ще одна функціональна
версія, яка використовує рекурсію та повертає новий об’єкт з 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) Те саме, що і 4), але в звичайному 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]
});
};
keysз object, так oі kочевидні. Але я думаю, це справа смаку.
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; }, {})
Якщо ви використовуєте lodash або underscore.js, ось просте рішення:
var obj = {name: 'John', age: null};
var compacted = _.pickBy(obj);
Це буде працювати лише з lodash 4, pre lodash 4 або underscore.js, use _.pick(obj, _.identity);
_.omit(obj, _.isUndefined)краще.
_.isUndefinedне опускає нулі, використовуй, _.omitBy(obj, _.isNil)щоб опустити і те, undefinedіnull
Найкоротший один вкладиш для ES6 +
Фільтр за все falsy значення ( "", 0, false, null, undefined)
Object.entries(obj).reduce((a,[k,v]) => (v ? (a[k]=v, a) : a), {})
Фільтр nullта undefinedзначення:
Object.entries(obj).reduce((a,[k,v]) => (v == null ? a : (a[k]=v, a)), {})
Фільтр ТІЛЬКИ null
Object.entries(obj).reduce((a,[k,v]) => (v === null ? a : (a[k]=v, a)), {})
Фільтр ТІЛЬКИ undefined
Object.entries(obj).reduce((a,[k,v]) => (v === undefined ? a : (a[k]=v, a)), {})
Рекурсивні рішення: Фільтри nullтаundefined
Для об'єктів:
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)), {});
Для об'єктів та масивів:
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ви будете перевіряти проти undefinedта null.
cleanEmptyrecursve рішення повертає порожній об'єкт {}для об'єктів Дати
Якщо комусь потрібна рекурсивна версія відповіді Оуена (та Еріка), ось це:
/**
* 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);
}
}
}
hasOwnPropertyвикористовується об'єктif(test.hasOwnProperty(i)) { ... }
JSON.stringify видаляє не визначені ключі.
removeUndefined = function(json){
return JSON.parse(JSON.stringify(json))
}
nullбуде розглядатися як undefinedвикористання функції заміни, для отримання додаткової інформації зверніться до цієї відповіді: stackoverflow.com/questions/286141 / ...
null. Спробуйте: let a = { b: 1, c: 0, d: false, e: null, f: undefined, g: [], h: {} }і тоді console.log(removeUndefined(a)). Питання було про undefinedі nullзначення.
Ви можете використовувати комбінацію параметра JSON.stringify, його замінника, і JSON.parseповернути його назад в об'єкт. Використання цього методу також означає, що заміна виконується для всіх вкладених ключів у вкладених об'єктах.
Приклад об’єкта
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]
}
]
};
Функція замінника
function replaceUndefinedOrNull(key, value) {
if (value === null || value === undefined) {
return undefined;
}
return value;
}
Очистіть об’єкт
exampleObject = JSON.stringify(exampleObject, replaceUndefinedOrNull);
exampleObject = JSON.parse(exampleObject);
Використання ramda # pickBy ви видалите всі null, undefinedі falseзначення:
const obj = {a:1, b: undefined, c: null, d: 1}
R.pickBy(R.identity, obj)
Як вказував @manroe, щоб falseвикористовувати значення isNil():
const obj = {a:1, b: undefined, c: null, d: 1, e: false}
R.pickBy(v => !R.isNil(v), obj)
(v) => !R.isNil(v)це, мабуть, кращий вибір для питання ОП, враховуючи, що falseабо інші фальшиві цінності також будуть відкинуті користувачемR.identity
Функціональний та незмінний підхід, .filterбез створення та без створення більшої кількості об'єктів, ніж потрібно
Object.keys(obj).reduce((acc, key) => (obj[key] === undefined ? acc : {...acc, [key]: obj[key]}), {})
obj[key] === undefinedнаobj[key] === undefined || obj[key] === null
const omitFalsy = obj => Object.keys(obj).reduce((acc, key) => ({ ...acc, ...(obj[key] && { [key]: obj[key] }) }), {});
ви можете зробити коротше з !умовою
var r = {a: null, b: undefined, c:1};
for(var k in r)
if(!r[k]) delete r[k];
Пам’ятайте про використання: як @semicolor оголосити в коментарях: Це також видалить властивості, якщо значення порожній рядок, помилкове або нульове
[null, undefined].includes(r[k])замість !r[k].
Коротше чисте рішення ES6, конвертуйте його в масив, використовуйте функцію фільтра та перетворіть його назад на об'єкт. Було б також легко зробити функцію ...
Btw. з цим .length > 0я перевіряю, чи є порожній рядок / масив, тому він видалить порожні ключі.
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; }, {});
nullі просто undefinedбуло б просто використовувати MY_OBJECT[f] != null. Ваше поточне рішення видаляє все, крім порожніх рядків / списків, і видає помилку, коли значенняnull
filter, було б читабельніше.
omitробить loadash , вам потрібно перевірити, чи існує Object.keysconst omit = (obj, filter) => obj && Object.keys(obj).filter(key => !filter(obj[key])).reduce((acc,key) => {acc[key] = obj[key]; return acc}, {});
Ви можете зробити рекурсивне видалення в одному рядку, використовуючи аргумент-замінник json.stringify
const removeNullValues = obj => (
JSON.parse(JSON.stringify(obj, (k,v) => v ?? undefined))
)
Використання:
removeNullValues({a:{x:1,y:null,z:undefined}}) // Returns {a:{x:1}}
Як згадується в коментарі Еммануеля, ця методика працювала лише в тому випадку, якщо ваша структура даних містить лише типи даних, які можна ввести у формат JSON (рядки, числа, списки тощо).
(Ця відповідь був оновлений , щоб використовувати новий оператор Nullish коалесцирует в залежності від потреб підтримки браузера ви можете використовувати цю функцію замість :. (k,v) => v!=null ? v : undefined)
NaNдо nullякої не видаляються.
Якщо ви хочете 4 рядки чистого рішення 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;
Або якщо ви віддаєте перевагу більш читаній версії:
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;
}
Це збереже булеві значення і також очистить масиви. Він також зберігає оригінальний об'єкт, повертаючи очищену копію.
У мене такий же сценарій у моєму проекті і досягнуто, використовуючи наступний метод.
Він працює з усіма типами даних, кілька згаданих вище не працює з датами та порожніми масивами.
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;
}
передайте будь-який об’єкт цій функції deleteEmptyKeysFromObject ()
Для глибокого пошуку я використав наступний код, можливо, він буде корисний для всіх, хто переглядає це питання (він не використовується для циклічних залежностей):
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;
}
Якщо ви не хочете мутувати на місці, але повернути клон з вилученим null / undefined, ви можете скористатися функцією зменшення 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;
}, {});
}
Щоб скласти скаргу на відповідь Бена про те, як вирішити цю проблему за допомогою лодаша _.pickBy, ви також можете вирішити цю проблему в сестринській бібліотеці: Underscore.js 's _.pick.
var obj = {name: 'John', age: null};
var compacted = _.pick(obj, function(value) {
return value !== null && value !== undefined;
});
Див.: Приклад JSFiddle
Якщо комусь потрібно видалити undefinedзначення з об'єкта при глибокому пошуку, використовуючи lodashкод, який я використовую. Це досить просто змінити, щоб видалити всі порожні значення ( 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;
}, {});
}
З Лодашем:
_.omitBy({a: 1, b: null}, (v) => !v)
Якщо ви використовуєте eslint і хочете уникнути відключення правила no-param-reasign, ви можете використовувати Object.assign у поєднанні з .reduce та обчисленою назвою властивості для досить елегантного рішення 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 }
Ось функціональний спосіб видалення nullsз Об'єкта за допомогою ES6 без мутації об'єкта лише за допомогою reduce:
const stripNulls = (obj) => {
return Object.keys(obj).reduce((acc, current) => {
if (obj[current] !== null) {
return { ...acc, [current]: obj[current] }
}
return acc
}, {})
}
stripNullsфункції він використовує посилання поза сферою функції акумулятора; і це також змішує проблеми, фільтруючи в межах функції акумулятора. 😝 (наприклад Object.entries(o).filter(([k,v]) => v !== null).reduce((o, [k, v]) => {o[k] = v; return o;}, {});) Так, він
Ви також можете використовувати ...синтаксис розповсюдження, використовуючи forEachщось подібне:
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)
Ми можемо використовувати JSON.stringify та JSON.parse для видалення порожніх атрибутів з об’єкта.
jsObject = JSON.parse(JSON.stringify(jsObject), (key, value) => {
if (value == null || value == '' || value == [] || value == {})
return undefined;
return value;
});
{} != {}і [] != []), але в іншому випадку підхід діє
Ось комплексна рекурсивна функція (спочатку заснована на функції від @chickens), яка буде:
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
}
ВИКОРИСТАННЯ:
// 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]))
Якщо ви віддаєте перевагу чистий / функціональний підхід
const stripUndef = obj =>
Object.keys(obj)
.reduce((p, c) => ({ ...p, ...(x[c] === undefined ? { } : { [c]: x[c] })}), {});