Удалить пустые атрибуты из объекта в Javascript

267

Как удалить все атрибуты, которые есть undefinedили nullв объекте JavaScript?

(Вопрос похож на этот для массивов)

Abhijit
источник
19
Настоятельно рекомендуем людям игнорировать топ-рейтинг и переходить к версиям ES6 / ES7 здесь, stackoverflow.com/a/38340730/124486
Эван Кэрролл
2
Также ES6 one лайнеры без мутирующего объекта находится здесь: stackoverflow.com/a/57625661/1602301
цыплята

Ответы:

184

Вы можете перебрать объект:

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];
    }
  }
}

Несколько замечаний о нуле против неопределенных:

test.test1 === null; // true
test.test1 == null; // true

test.notaprop === null; // false
test.notaprop == null; // true

test.notaprop === undefined; // true
test.notaprop == undefined; // true
Оуэн
источник
2
Добавлена ​​быстрая коррекция. Необъявленная переменная «i» попадет во внешнюю область видимости, если этот фрагмент когда-либо использовался в функции.
Эрик Нгуен
4
Вы можете упростить (test [i] === null || test [i] === undefined) до (test [i] == null)
jaf0
Здравствуйте, @EricNguyen, в отличие от C и других языков, javascript не имеет области видимости блока для переменных (только область функции), поэтому переменная i всегда будет попадать в область видимости после блока for .
Херардо Лима
1
@GerardoLima, да. Я предполагал, что все это будет заключено в функцию. Что я имел в виду (предполагая, что все это заключено в функцию), так это то, что вам нужно объявление var, иначе я попаду даже за пределы области действия функции.
Эрик Нгуен
Это также перебирает прототип примитивного объекта, что в большинстве случаев нежелательно. stackoverflow.com/a/2869372/1612318
Rotareti
428

Используя некоторые ES6 / ES2015 :

1) Простой однострочник для удаления элементов в строке без присваивания:

Object.keys(myObj).forEach((key) => (myObj[key] == null) && delete myObj[key]);

jsbin

2) Этот пример был удален ...

3) Первый пример, написанный как функция:

const removeEmpty = obj => {
  Object.keys(obj).forEach(key => obj[key] == null && delete obj[key]);
};

jsbin

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
  });
};

jsbin

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.
      {}
    );

jsbin

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]
  });
};

jsbin

Rotareti
источник
3
@AugustinRiedinger Когда мне приходится выбирать между разрывом строки и аббревиатурой, я иногда использую аббревиатуру, если считаю аббревиатуру меньшим злом. Код в 5) не сложно рассуждать, и это функция, которая удаляет пустые keysиз object, так oи kочевидны. Но я думаю, это вопрос вкуса.
Rotareti
3
Первая версия со вкусом ES5:Object.keys(myObj).forEach(function (key) {(myObj[key] == null) && delete myObj[key]});
Нейротрансмиттер
1
Одна строка без функции:Object.entries(myObj).reduce((acc, [key, val]) => { if (val) acc[key] = val; return acc; }, {})
Пол Слм
7
Поскольку мы стараемся быть тщательными, было бы неплохо увидеть неизменное решение. Они видоизменяют исходный объект и обманчиво возвращают объект, который на самом деле не нужен, потому что объект был мутирован. Новички будут захватывать возвращаемое значение объекта и удивляться, почему их исходный объект также изменяется.
Майк Маклин
2
5) Не работает с массивами (Object.keys будет возвращать номера позиций массива в качестве ключа для элементов). Возможно, у других есть эта проблема, но я обнаружил это при тестировании 5.
Eelco
95

Если вы используете lodash или underscore.js, вот простое решение:

var obj = {name: 'John', age: null};

var compacted = _.pickBy(obj);

Это будет работать только с lodash 4, pre lodash 4 или underscore.js, use _.pick(obj, _.identity);

Бен
источник
1
Brilliant! Спасибо! К вашему сведению, для меня не было очевидно, что вы можете использовать его также так: foo (). Then (_. PickBy); // отфильтровываем пустые результаты
Мацей Гурбан
29
Обратите внимание, что это не будет иметь желаемого результата, если объект содержит ложные значения, такие как 0 или пустые строки. Тогда _.omit(obj, _.isUndefined)лучше.
JHH
5
@JHH _.isUndefinedне пропускает нули, используйте _.omitBy(obj, _.isNil)для пропуска обоих undefinedиnull
Лукаш Виктор
@LukaszWiktor Правильно, вопрос задавался неопределенным или нулевым.
JHH
88

Самый короткий лайнер для 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)), {});
  } 
}
цыплята
источник
10
Это должен быть единственный ответ! Каждый из этих фрагментов будет генерировать новый объект, в котором старый объект не будет видоизменяться. Это предпочтительнее! Небольшое примечание, если вы просто используете, v == nullвы будете проверять undefinedи null.
Megajin
то cleanEmptyrecursve решение возвращает пустой объект {}для объектов Даты
Эммануэль NK
Немного больше разборчивости в одних лайнерах сделало бы их потрясающими !!
zardilior
39

Если кому-то нужна рекурсивная версия ответа Оуэна (и Эрика), вот он:

/**
 * 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);
        }
    }
}
Wumms
источник
После того, как цикл for начинается, вы должны проверить, что объект hasOwnPropertyиспользуетif(test.hasOwnProperty(i)) { ... }
Augie Gardner
@AugieGardner Мне интересно, почему вы хотите это проверить - объясните, если хотите. (Разве это не помешает проверке унаследованных свойств?)
Wumms
24

JSON.stringify удаляет неопределенные ключи.

removeUndefined = function(json){
  return JSON.parse(JSON.stringify(json))
}
Александр Фарбер
источник
Это не сработало для меня для глубокого предмета, но ответ Вумма выше сработал .
Суман
1
Если вам нужно nullобращаться undefinedс функцией замены, для получения дополнительной информации обратитесь к этому ответу: stackoverflow.com/questions/286141/…
Hooman Askari
Просто знайте, что это не удаляет nullзначения. Попробуй: let a = { b: 1, c: 0, d: false, e: null, f: undefined, g: [], h: {} }а потом console.log(removeUndefined(a)). Вопрос был о undefinedи nullценности.
mayid
13

Вы, вероятно, ищете deleteключевое слово.

var obj = { };
obj.theProperty = 1;
delete obj.theProperty;
yfeldblum
источник
4
Это то, что он делает выше, это также все еще оставляет неопределенным в объекте.
Джош Бедо
10

Простейшее возможное решение Lodash вернуть объект с nullи undefinedзначениями отфильтрованы.

_.omitBy(obj, _.isNil)

JeffD23
источник
пока это самое чистое решение!
Джи Мок
9

Вы можете использовать комбинацию 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);

Пример CodePen

Алекс Мюллер
источник
6

Использование 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)
Amio.io
источник
1
(v) => !R.isNil(v)вероятно, лучший выбор для вопроса ОП, учитывая, что falseили другие ложные значения также будут отклоненыR.identity
Манро
6

Функциональный и неизменный подход, без .filterи без создания большего количества объектов, чем необходимо

Object.keys(obj).reduce((acc, key) => (obj[key] === undefined ? acc : {...acc, [key]: obj[key]}), {})
peralmq
источник
Очень лаконичный ответ. Чтобы также добавить нулевую проверку, просто замените obj[key] === undefinedнаobj[key] === undefined || obj[key] === null
user3658510
Небольшая вариация вышеупомянутого подхода: вы также можете условно распространяться в свойстве truey obj, например, такconst omitFalsy = obj => Object.keys(obj).reduce((acc, key) => ({ ...acc, ...(obj[key] && { [key]: obj[key] }) }), {});
Кевин К.
6

Вы можете сделать рекурсивное удаление в одной строке, используя аргумент заменителя json.stringify

const removeEmptyValues = obj => (
  JSON.parse(JSON.stringify(obj, (k,v) => v ?? undefined))
)

Использование:

removeEmptyValues({a:{x:1,y:null,z:undefined}}) // Returns {a:{x:1}}

Как упоминалось в комментарии Эммануэля, этот метод работал, только если ваша структура данных содержит только типы данных, которые могут быть переведены в формат JSON (строки, числа, списки и т. Д.).

(Этот ответ был обновлен , чтобы использовать новый оператор Nullish коалесцирующего в зависимости от потребностей поддержки браузера вы можете использовать эту функцию вместо:. (k,v) => v!=null ? v : undefined)

Скотти Джеймисон
источник
1
это преобразует объекты Date в строки, преобразования NaNв nullкоторые не удаляются.
Эммануэль НК
5

Вы можете сделать короче с !условием

var r = {a: null, b: undefined, c:1};
for(var k in r)
   if(!r[k]) delete r[k];

Помните при использовании: как @semicolor объявляет в комментариях: это также приведет к удалению свойств, если значением является пустая строка, false или ноль

Nguyên
источник
11
Это также приведет к удалению свойств, если значением является пустая строка, false или ноль.
точка с запятой
3
Это было именно то, что я искал, чтобы удалить ненужные поля из запроса JSON. Спасибо!
Phrozen
Используйте [null, undefined].includes(r[k])вместо !r[k].
selmansamet
5

Короче чистое решение 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; }, {});

JS BIN https://jsbin.com/kugoyinora/edit?js,console

Майкл Дж. Зойдл
источник
1
Хорошее функциональное решение
puiu
Мне это нравится! Но я думаю, чтобы удалить все, nullи undefinedбыло бы проще просто использовать MY_OBJECT[f] != null. Ваше текущее решение удаляет все, кроме непустых строк / списков и выдает ошибку, когда значенияnull
Rotareti
Правильно, вы также можете использовать / цепочку нескольких filter, будет более читабельным.
Майкл Дж.
Если вы обобщите это немного, я думаю, вы приблизитесь к тому, что omitделает loadash , вам нужно проверить, существует ли obj перед вызовом Object.keys:const omit = (obj, filter) => obj && Object.keys(obj).filter(key => !filter(obj[key])).reduce((acc,key) => {acc[key] = obj[key]; return acc}, {});
icc97
Хорошо, но любое целочисленное значение будет удалено при таком подходе.
Ghis
4

Если вы хотите 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;
}

Это сохранит логические значения и также очистит массивы. Он также сохраняет исходный объект, возвращая очищенную копию.

DaniOcean
источник
4

У меня такой же сценарий в моем проекте, и я достиг этого, используя следующий метод.

Он работает со всеми типами данных, немногие из упомянутых выше не работают с датой и пустыми массивами.

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;
}

передать любой объект этой функции removeEmptyKeysFromObject ()

Бхарат Муппа
источник
4

Для глубокого поиска я использовал следующий код, может быть, он будет полезен всем, кто смотрит на этот вопрос (его нельзя использовать для циклических зависимостей):

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;
    }
Сэм
источник
3

Если вы не хотите изменять на месте, но возвращаете клон с удаленным значением 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;
  }, {});
}
bsyk
источник
3

Вместо удаления свойства вы также можете создать новый объект с ключами, которые не равны нулю.

const removeEmpty = (obj) => {
  return Object.keys(obj).filter(key => obj[key]).reduce(
    (newObj, key) => {
      newObj[key] = obj[key]
      return newObj
    }, {}
  )
}
Джин Чжао
источник
3

Чтобы piggypack на ответ Бена о том , как решить эту проблему с помощью lodash - х _.pickBy, вы можете решить эту проблему в библиотеке сестры: Underscore.js «s _.pick.

var obj = {name: 'John', age: null};

var compacted = _.pick(obj, function(value) {
  return value !== null && value !== undefined;
});

Смотрите пример JSFiddle

Алекс Джонсон
источник
1
это возвращает пустой массив, также вы изменили имя obj на object
Стивен Дюмон
Спасибо, Стивен! Как насчет сейчас? Я обновил свой ответ, добавив ссылку на JSFiddle.
Алекс Джонсон
попробуйте использовать _.omit (obj, _.isEmpty); это более концептуально чисто и будет включать пустую строку.
Стивен Дюмон
3

помощник сокращения может сделать трюк (без проверки типа) -

const cleanObj = Object.entries(objToClean).reduce((acc, [key, value]) => {
      if (value) {
        acc[key] = value;
      }
      return acc;
    }, {});
Yinon
источник
2

Если кому-то нужно удалить 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;
  }, {});
}
Лукаш Ягодзиньски
источник
1

С Лодашем:

_.omitBy({a: 1, b: null}, (v) => !v)
Дана Вудман
источник
1

Если вы используете eslint и хотите избежать срабатывания правила no-param-reassign, вы можете использовать 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 }
dpmott
источник
1

Вот функциональный способ удаления 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;}, {});) Да, он будет дважды проходить по фильтрованным элементам, но реализованная потеря производительности там незначительна.
Джейсон Каст
1

Вы также можете использовать ...синтаксис распространения, используя 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);
Хардик Питва
источник
1

Очистить объект на месте

// 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)
Бен Карп
источник
Это один хороший, возможно , один вкладыш, раствор
Rekam
1

Мы можем использовать JSON.stringify и JSON.parse для удаления пустых атрибутов из объекта.

jsObject = JSON.parse(JSON.stringify(jsObject), (key, value) => {
               if (value == null || value == '' || value == [] || value == {})
                   return undefined;
               return value;
           });
Вардаман ПК
источник
Этот трюк действительно действителен, если вы гарантируете, что Obj является JSON-сериализуемым. И это работает глубоко.
Сополи
Недопустимое сравнение массивов и объектов ( {} != {}и [] != []), но в противном случае подход действителен
Aivaras
1

Вот полная рекурсивная функция (изначально основанная на функции @chickens), которая будет:

  • рекурсивно удалить то, что вы говорите defaults=[undefined, null, '', NaN]
  • Правильно обрабатывать обычные объекты, массивы и объекты Date
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]))

Эммануэль Н.К.
источник
0

Если вы предпочитаете чистый / функциональный подход

const stripUndef = obj => 
  Object.keys(obj)
   .reduce((p, c) => ({ ...p, ...(x[c] === undefined ? { } : { [c]: x[c] })}), {});
Питер Арон Зентаи
источник