Usuń puste atrybuty z obiektu w JavaScript


Odpowiedzi:


184

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

2
Dodano szybką korektę. Niezadeklarowana zmienna „i” wyciekłaby do zakresu zewnętrznego, gdyby ten fragment kodu był kiedykolwiek używany w funkcji.
— Eric Nguyen,

4
możesz uprościć (test [i] === null || test [i] === undefined) do (test [i] == null)
— jaf0

Cześć, @EricNguyen, w przeciwieństwie do C i kilku innych języków, javascript nie ma zasięgu blokowego dla zmiennych (tylko zakres funkcji), dlatego zmienna i zawsze przecieka do zakresu po bloku for .
— Gerardo Lima,

1
@GerardoLima, tak. W pewnym sensie zakładałem, że wszystko to będzie opakowane w funkcję. Co mam na myśli (zakładając, że jest to wszystko opakowane z funkcji) jest to, że trzeba deklarację var lub I będzie przeciekać nawet poza zakresem funkcji.
— Eric Nguyen

Spowoduje to również zapętlenie prototypu obiektu pierwotnego - co w większości przypadków nie jest pożądane. stackoverflow.com/a/2869372/1612318
— Rotareti,

427

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

jsbin

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

jsbin

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

jsbin

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

jsbin

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

jsbin


3
@AugustinRiedinger Kiedy muszę zdecydować między przełamaniem linii a skrótem, czasami wybieram skrót, jeśli uważam, że skrót jest mniejszym złem. Kod w 5) nie jest trudny do uzasadnienia i jest to funkcja, która usuwa puste keysz object, więc oi ksą oczywiste. Ale myślę, że to kwestia gustu.
— Rotareti,

3
Pierwsza wersja o smaku ES5:Object.keys(myObj).forEach(function (key) {(myObj[key] == null) && delete myObj[key]});
— Neurotransmitter

1
Jedna linia, bez funkcji:Object.entries(myObj).reduce((acc, [key, val]) => { if (val) acc[key] = val; return acc; }, {})
— Paul Slm

7
Ponieważ staramy się być dokładni, fajnie byłoby zobaczyć niezmienne rozwiązanie. Te mutują obiekt źródłowy i zwodniczo zwracają obiekt, który w rzeczywistości jest niepotrzebny, ponieważ obiekt został zmutowany. Początkujący przechwytują wartość zwracanego obiektu i zastanawiają się, dlaczego ich obiekt źródłowy został również zmodyfikowany.
— Mike McLin

2
5) Nie działa z tablicami (Object.keys zwróci numery pozycji tablicy jako klucz do elementów). Być może inni mają ten problem, ale znalazłem to podczas testowania 5.
— Eelco,

95

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


1
Znakomity! Dziękuję Ci! Dla ciebie nie było dla mnie oczywiste, że możesz użyć tego również w następujący sposób: foo (). Then (_. PickBy); // odfiltrowywanie pustych wyników
— Maciej Gurban

29
Zauważ, że nie przyniesie to pożądanego rezultatu, jeśli obiekt zawiera wartości fałszowania, takie jak 0 lub puste ciągi. To _.omit(obj, _.isUndefined)jest lepsze.
— JHH

5
@JHH _.isUndefinednie pomija zer , użyj, _.omitBy(obj, _.isNil)aby pominąć oba undefinedinull
— Łukasz Wiktor

@L ŁukaszWiktor Prawidłowo, pytanie zawierało wartość niezdefiniowaną lub zerową.
— JHH

85

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

10
To powinna być jedyna odpowiedź! Każdy z tych fragmentów wygeneruje nowy obiekt, w którym stary nie zostanie zmutowany. To jest lepsze! Mała uwaga, jeśli po prostu użyjesz v == null, sprawdzisz przeciwko undefinedi null.
— Megajin

te cleanEmptyrozwiązania recursve zwróci pusty obiekt {}dla obiektów Date
— Emmanuel NK

Nieco większa czytelność w jednym wkładce sprawiłaby, że byłyby niesamowite !!
— zardilior

39

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

Po rozpoczęciu pętli for należy sprawdzić, czy obiekt hasOwnPropertyużywaif(test.hasOwnProperty(i)) { ... }
— Augie Gardner,

@AugieGardner Jestem ciekawy, dlaczego chcesz to sprawdzić - proszę wyjaśnij, jeśli chcesz. (Czy nie zapobiegłoby to sprawdzeniu odziedziczonych właściwości?)
— Wumms,

24

JSON.stringify usuwa niezdefiniowane klucze.

removeUndefined = function(json){
  return JSON.parse(JSON.stringify(json))
}

Nie działało to dla mnie w przypadku głębokiego obiektu, ale powyższa odpowiedź Wumma ​​zadziałała .
— Suman

1
Jeśli chcesz nullbyć traktowany jak undefinedskorzystaj z funkcji zastępowania, więcej informacji znajdziesz w tej odpowiedzi: stackoverflow.com/questions/286141/...
— Hooman Askari

Pamiętaj, że to nie usuwa 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.
— mayid

13

Prawdopodobnie szukasz deletesłowa kluczowego.

var obj = { };
obj.theProperty = 1;
delete obj.theProperty;

4
To, co robi powyżej, również pozostawia niezdefiniowany w obiekcie.
— Josh Bedo

10

Najprostsze możliwe rozwiązanie Lodash, aby zwrócić obiekt z odfiltrowanymi wartościami nulli undefined.

_.omitBy(obj, _.isNil)


to jak dotąd najczystsze rozwiązanie!
— Jee Mok

9

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

Przykład CodePen


6

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)

1
(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
— manroe

6

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]}), {})

Bardzo zwięzła odpowiedź. Aby dodać również kontrolę zerową, po prostu zamień obj[key] === undefinednaobj[key] === undefined || obj[key] === null
— user3658510

niewielka odmiana powyższego podejścia: możesz również warunkowo rozprzestrzenić się na prawdę obj właściwość obj.const omitFalsy = obj => Object.keys(obj).reduce((acc, key) => ({ ...acc, ...(obj[key] && { [key]: obj[key] }) }), {});
— Kevin K.,

5

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


11
Spowodowałoby to również usunięcie właściwości, jeśli wartością jest pusty ciąg, fałsz lub zero.
— Semicolon

3
Właśnie tego szukałem, aby usunąć niechciane pola z żądania JSON. Dzięki!
— Phrozen,

Użyj [null, undefined].includes(r[k])zamiast !r[k].
— selmansamet

5

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

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


1
Ładne rozwiązanie funkcjonalne
— puiu

Lubię to! Ale myślę, że usunę wszystko 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
— Rotareti

Racja, możesz również użyć / łańcucha wielu filter, byłoby bardziej czytelne.
— Michael J. Zoidl,

Jeśli nieco to uogólnisz, myślę, że zbliżasz się do tego, co robi loadash 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}, {});
— icc97

Fajnie, ale każda wartość całkowita zostanie usunięta przy takim podejściu.
— Ghis,

5

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)


1
Spowoduje to konwersję obiektów Date na ciągi znaków, NaNna nullktóre nie zostaną usunięte.
— Emmanuel NK

4

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ę.


4

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 ()


4

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

3

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

3

Zamiast usunąć właściwość, możesz również utworzyć nowy obiekt z kluczami, które nie mają wartości null.

const removeEmpty = (obj) => {
  return Object.keys(obj).filter(key => obj[key]).reduce(
    (newObj, key) => {
      newObj[key] = obj[key]
      return newObj
    }, {}
  )
}

3

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


1
to zwraca pustą tablicę, zmieniłeś także nazwę obiektu na obiekt
— Stephen DuMont,

Dziękuję Stephen! A teraz? Zaktualizowałem swoją odpowiedź, aby zawierała link JSFiddle.
— Alex Johnson

spróbuj użyć _.omit (obj, _.isEmpty); jest to bardziej koncepcyjnie czyste i będzie zawierać pusty ciąg.
— Stephen DuMont

3

pomocnik redukcji może zrobić lewę (bez sprawdzania typu) -

const cleanObj = Object.entries(objToClean).reduce((acc, [key, value]) => {
      if (value) {
        acc[key] = value;
      }
      return acc;
    }, {});

2

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


1

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 }

1

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
  }, {})
}

Komentarz Trolla Dwie rzeczy dotyczące tego, że jest to wzorzec funkcjonalny: w ramach 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,
— Jason Cust,

1

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

1

Wyczyść obiekt na miejscu

// General cleanObj function
const cleanObj = (valsToRemoveArr, obj) => {
   Object.keys(obj).forEach( (key) =>
      if (valsToRemoveArr.includes(obj[key])){
         delete obj[key]
      }
   })
}

cleanObj([undefined, null], obj)

Czysta funkcja

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)

To jest dobre, być może jedno-liniowe rozwiązanie
— rekam

1

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

Ta sztuczka jest faktycznie ważna, o ile upewnisz się, że Obj ma możliwość serializacji JSON. I działa również głęboko.
— Polv

Niepoprawne porównanie tablic i obiektów ( {} != {}i [] != []), ale w innym przypadku poprawne jest podejście
— Aivaras

1

Oto kompleksowa funkcja rekurencyjna (pierwotnie oparta na funkcji @chickens), która:

  • rekurencyjnie usuwaj to, co mówisz defaults=[undefined, null, '', NaN]
  • Prawidłowo obsługuj zwykłe obiekty, tablice i obiekty daty
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]))


0

Jeśli wolisz podejście czyste / funkcjonalne

const stripUndef = obj => 
  Object.keys(obj)
   .reduce((p, c) => ({ ...p, ...(x[c] === undefined ? { } : { [c]: x[c] })}), {});
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.