190

Is there a clean way to remove undefined fields from an object?

i.e.

> var obj = { a: 1, b: undefined, c: 3 }
> removeUndefined(obj)
{ a: 1, c: 3 }

I came across two solutions:

_.each(query, function removeUndefined(value, key) {
  if (_.isUndefined(value)) {
    delete query[key];
  }
});

or:

_.omit(obj, _.filter(_.keys(obj), function(key) { return _.isUndefined(obj[key]) }))
Damian
  • 2,223
  • 3
  • 16
  • 12

9 Answers9

327

A one-liner using ES6 arrow function and ternary operator:

Object.keys(obj).forEach(key => obj[key] === undefined ? delete obj[key] : {});

Or use short-circuit evaluation instead of ternary: (@Matt Langlois, thanks for the info!)

Object.keys(obj).forEach(key => obj[key] === undefined && delete obj[key])

Same example using if statement:

Object.keys(obj).forEach(key => {
  if (obj[key] === undefined) {
    delete obj[key];
  }
});

If you want to remove the items from nested objects as well, you can use a recursive function:

const removeEmpty = (obj) => {
  let newObj = {};
  Object.keys(obj).forEach((key) => {
    if (obj[key] === Object(obj[key])) newObj[key] = removeEmpty(obj[key]);
    else if (obj[key] !== undefined) newObj[key] = obj[key];
  });
  return newObj;
};
Rotareti
  • 49,483
  • 23
  • 112
  • 108
  • 24
    You actually don't even need the ternary operator. Instead you can do `(obj[key]===undefined&& delete obj[key])` The reason this works is because and uses short-circuit evaluation, so once the first check fails the second isn't even evaluated. – Matt Langlois Jul 20 '16 at 19:39
  • 2
    Even better! I updated the answer. Thanks for mentioning it :) – Rotareti Jul 20 '16 at 21:17
  • 7
    `!obj[key]` will not only remove `null`, `''` and `undefined`, but also remove `0` and `NaN`. – pandark Feb 23 '18 at 20:45
  • 14
    SO isn't a code-golfing site - clean, readable code is much more important than *as short as possible* code. The conditional operator is appropriate when you need to do something with the result of the expression, which is not the case here. If you just need to imitate `if/else`, I think it would be best to just use `if/else`. – CertainPerformance Aug 01 '18 at 06:13
  • 1
    @CertainPerformance Fair point. I added an example using an `if` expression. – Rotareti Aug 01 '18 at 12:16
  • @Rotareti arrow function will break in IE 11 – sgajera Oct 22 '18 at 06:29
  • this function will modify the passed object, sometimes a nonmutating variant might be desired – fabb Jan 21 '19 at 10:01
  • is it worth checking the property exists first? `key in obj && obj[key] === undefined && delete obj[key]` – Anthony Johnston Jan 10 '20 at 10:28
  • Poor coding practice, not using the returned ternary result in the top code. Or the binary shortcut returned Boolean. Same occurs with any C based language including C (excluding optimizer). Just stating my down-vote. *summarized – TamusJRoyce Jan 14 '20 at 17:56
  • @TamusJRoyce I agree, I wouldn't use ternary and short-circuit like in the first 2 examples in general. But it's useful in situations in which your code needs to stay declarative. For example, I see this kind of code a lot in React's JSX templates, where it makes sense (IMHO). – Rotareti Jan 14 '20 at 19:01
  • 3
    Just a warning, the recursive function breaks objects with arrays in them. It needs an additional case to handle arrays. – Erwin Apr 22 '21 at 21:11
  • @Erwin yeah I just had a bug due to this behavior. Have you fixed it? Can you or anyone else edit the answer? – Henrique Bruno Nov 09 '21 at 22:04
  • I wouldn't agree with this answer being accepted. Although it sorts out the problem, the immutable way should be preferred. Since I put those usually in classes for the purpose of generating "update" queries, this is what I use: `Object.keys(this) .reduce((prev, curr) => this[curr] !== undefined ? { ...prev, [curr]: this[curr] } : prev, {})` – JFCorleone Aug 06 '22 at 11:00
107

I prefer to use something like Lodash:

import { pickBy, identity } from 'lodash'

const cleanedObject = pickBy(originalObject, identity)

Note that the identity function is just x => x and its result will be false for all falsy values. So this removes undefined, "", 0, null, ...

If you only want the undefined values removed you can do this:

const cleanedObject = pickBy(originalObject, v => v !== undefined)

It gives you a new object, which is usually preferable over mutating the original object like some of the other answers suggest.

Thijs Koerselman
  • 21,680
  • 22
  • 74
  • 108
  • 4
    The second argument to `pickBy` defaults to `identity`, so this can be simplified to `const cleanedObject = pickBy(originalObject)` if desired. – dvanoni Jan 21 '21 at 06:14
  • 11
    Or your code runs on the back-end and you don't worry about bundle size. Or your front-end bundler uses tree shaking and/or rewrites the Lodash imports (Babel plugin) so that you only import what you use. So I don't think it's right to say that Lodash is way too bloated by definition. It depends. – Thijs Koerselman Feb 16 '22 at 15:06
  • It didn't remove nested null items – Royer Adames Jul 22 '22 at 18:31
  • Null is not the same as undefined. I avoid using null as much as possible. Here are some details https://hamednourhani.gitbooks.io/typescript-book/content/docs/tips/null.html This topic was not about null or recursion. – Thijs Koerselman Jul 24 '22 at 06:32
97

Use JSON Utilities

Overview

Given an object like:

var obj = { a: 1, b: undefined, c: 3 }

To remove undefined props in an object we can use nested JSON methods stringify and parse like so:

JSON.parse(JSON.stringify(obj))

Live Example

var obj = { a: 1, b: undefined, c: 3 }
var output = JSON.parse(JSON.stringify(obj));

console.log(output)

Limitations and warnings

Depending on how Javascript is implemented.

  • It is possible that undefined will be converted to null instead of just being removed.
  • Nested Object, Array will be converted to strings
  • Date, time values also converted to strings

Tested

The above code was tested in Firefox, Chrome, and Node 14.18.1 and removed "b" from all obj arrays. Still I recommend exercising caution using this method unless you are in a stable environment (such as cloud functions or docker) I would not rely on this method client side.

nmanikiran
  • 2,866
  • 15
  • 19
  • 5
    this will replace the `undefined` with `null` and the entries are still there. – Glenn Plas Jun 15 '17 at 12:24
  • 3
    @GlennPlas add a plnkr https://plnkr.co/edit/wP37G6BA5uJPSFz6xLTq?p=preview check browser console for output – nmanikiran Jun 15 '17 at 12:32
  • 1
    Indeed, strange I tested this in a project and it didn't work (I was using geojson objects and tried to clean out undefined features ), but this example indeed does what it says. – Glenn Plas Jun 17 '17 at 14:18
  • 1
    Actually, I recall the issue now, I had undefined keys, not values of valid keys. probably was a bit too quick to comment here. Tx. – Glenn Plas Jun 17 '17 at 14:22
  • 61
    Guys, this might look simple, but date objects will be converted to string. Beware – sowdri Jun 12 '18 at 04:07
  • 1
    This is very expensive on large objects – Kmaid Aug 05 '18 at 08:53
  • 3
    Short but slow, and only works for simple values. – Vidar Sep 02 '18 at 06:19
  • 10
    This is a hack more than anything. Formatting code to a string and parsing it back to code just to mutate something that can easily be done programatically? The unintentional side-effects (on Date for example) and computational inefficiency make that this answer should be downvoted IMO. – Thijs Koerselman Dec 26 '18 at 19:27
  • Keep in mind that this doesn't work with null values – Yulian Jan 14 '19 at 17:35
  • JSON.stringify(value[, replacer[, space]]) - if you use your own replacer, it will work. There is no magic if you understand how the default replacer works. For older browsers, this method may actually be faster for large objects. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify – TamusJRoyce Jan 14 '20 at 12:44
  • JSON serialization is surprisingly slow. The time scales exponentially, not linearly, with the object size, also good luck with circular references. – Vicary Oct 08 '20 at 06:50
37

Because it doesn't seem to have been mentioned, here's my preferred method, sans side effects or external dependencies:

const obj = {
  a: 1,
  b: undefined
}

const newObject = Object.keys(obj).reduce((acc, key) => {
  const _acc = acc;
  if (obj[key] !== undefined) _acc[key] = obj[key];
  return _acc;
}, {})

console.log(newObject)
// Object {a: 1}


// UPDATE: briefer version from @nicholas-hamilton with fewer assignments
const newObject2 = Object.keys(obj).reduce(
  (acc, key) =>
    obj[key] === undefined ? { ...acc } : { ...acc, [key]: obj[key] },
  {},
);
console.log(newObject2)
// Object {a: 1}
ptim
  • 14,902
  • 10
  • 83
  • 103
  • 3
    btw, I'm aliasing `_acc` to avoid the eslint error [no-param-reassign](http://eslint.org/docs/rules/no-param-reassign) – ptim Dec 02 '16 at 03:52
  • 1
    I started using the `filter` + `forEach` and ended up transforming it to a `reduce` like this. +1 – David May 28 '18 at 17:38
  • 12
    `Object.keys(obj).reduce((acc, key) => obj[key] === undefined ? {...acc} : {...acc, [key] : obj[key]} , {})` – Nicholas Hamilton Dec 02 '20 at 21:50
  • @NicholasHamilton do you have to spread the first `acc`? Maybe just ...`? acc : {...acc, [key]: obj[key]}`... ? – sleighty Jan 16 '23 at 01:47
18

This solution also avoids hasOwnProperty() as Object.keys returns an array of a given object's own enumerable properties.

Object.keys(obj).forEach(function (key) {
 if(typeof obj[key] === 'undefined'){
    delete obj[key];
  }
});

and you can add this as null or '' for stricter cleaning.

Alvaro Pinot
  • 251
  • 3
  • 6
8

Here's a plain javascript (no library required) solution:

function removeUndefinedProps(obj) {
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop) && obj[prop] === undefined) {
            delete obj[prop];
        }
    }
}

Working demo: http://jsfiddle.net/jfriend00/djj5g5fu/

jfriend00
  • 683,504
  • 96
  • 985
  • 979
3

Mhh.. I think @Damian asks for remove undefined field (property) from an JS object. Then, I would simply do :

for (const i in myObj) {
    if (typeof myObj[i] === 'undefined') {
        delete myObj[i]; 
    }
}

Short and efficient solution, in (vanilla) JS ! Example :

const myObj = {
  a: 1,
  b: undefined,
  c: null, 
  d: 'hello world'
};

for (const i in myObj) {
  if (typeof myObj[i] === 'undefined') {
    delete myObj[i];
  }
}

console.log(myObj);
coolaj86
  • 74,004
  • 20
  • 105
  • 125
Dam Fa
  • 448
  • 4
  • 16
2

This one is easy to remember, but might be slow. Use jQuery to copy non-null properties to an empty object. No deep copy unless you add true as first argument.

myObj = $.extend({}, myObj);
Fredrik
  • 587
  • 4
  • 7
0

Another Javascript Solution

for(var i=0,keys = Object.keys(obj),len=keys.length;i<len;i++){ 
  if(typeof obj[keys[i]] === 'undefined'){
    delete obj[keys[i]];
  }
}

No additional hasOwnProperty check is required as Object.keys does not look up the prototype chain and returns only the properties of obj.

DEMO

Prabhu Murthy
  • 9,031
  • 5
  • 29
  • 36
  • Except `Object.keys()` has it's own overhead in creating an entire array of the keys and it requires at least IE 9. – jfriend00 Aug 21 '14 at 08:24