Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to delete recursively undefined properties from an object - while keeping the constructor chain?

This is a question similar to How to remove undefined and null values from an object using lodash?. However, the solutions proposed there do not conserve the constructor. In addition to that, I want to only delete those keys which starts, say with '_'.

Here is what I am looking for, and can't seem to manage to get from lodash :

Input : new Cons({key1 : 'value1', key2 : {key21 : 'value21', _key22: undefined}, key3: undefined, _key4 : undefined})

Output : {key1 : 'value1', key2 : {key21 : 'value21'}, key3: undefined}

where for example function Cons(obj){_.extend(this, obj)}

I have a solution with omitBy using lodash, however, I loose the constructor information (i.e. I cannot use instanceof Cons anymore to discriminate the object constructor). forIn looked like a good candidate for the recursive traversal but it only provides me with the value and the key. I also need the path in order to delete the object (with unset).

Please note that:

  • the object is any valid javascript object
  • the constructor is any javascript valid constructor, and the object comes with the constructor already set.
  • the resulting object must have instanceof whatevertheconstructorwas still true

Is there a better solution (with lodash or else)?

like image 580
user3743222 Avatar asked May 16 '16 04:05

user3743222


People also ask

How do you remove undefined values from an object?

To remove all undefined values from an object:Use the Object. keys() method to get an array of the object's keys. Use the forEach() method to iterate over the array and delete all undefined values using the delete operator.

How do you remove undefined and null values from an object using Lodash?

To remove a null from an object with lodash, you can use the omitBy() function. If you want to remove both null and undefined , you can use . isNil or non-strict equality.

How do you remove undefined?

How can I remove undefined in JavaScript? An undefined value automatically gets assigned in JavaScript, where no value has been explicitly assigned. To remove all undefined values from the array, you can use the filter() method.

Is null or undefined Lodash?

Lodash helps in working with arrays, strings, objects, numbers, etc. The _. isNil() method is used to check if the value is null or undefined. If the value is nullish then returns true otherwise it returns false.


2 Answers

You can create a function that recursively omits keys through the use of omitBy() and mapValues() as an assisting function for traversing keys recursively. Also note that this also supports array traversal for objects with nested arrays or top level arrays with nested objects.

function omitByRecursively(value, iteratee) {
  var cb = v => omitByRecursively(v, iteratee);
  return _.isObject(value)
    ? _.isArray(value)
      ? _.map(value, cb)
      : _(value).omitBy(iteratee).mapValues(cb).value()
    : value;
}

function Cons(obj) { 
  _.extend(this, omitByRecursively(obj, (v, k) => k[0] === '_'));
}

Example:

function omitByRecursively(value, iteratee) {
  var cb = v => omitByRecursively(v, iteratee);
  return _.isObject(value)
    ? _.isArray(value)
      ? _.map(value, cb)
      : _(value).omitBy(iteratee).mapValues(cb).value()
    : value;
}

function Cons(obj) { 
  _.extend(this, omitByRecursively(obj, (v, k) => k[0] === '_'));
}

var result = new Cons({
  key1 : 'value1', 
  key2 : {
    key21 : 'value21', 
    _key22: undefined
  }, 
  key3: undefined,
  _key4 : undefined,
  key5: [
    {
      _key: 'value xx',
      key7: 'value zz',
      _key8: 'value aa'
    }
  ]
});

console.log(result);
.as-console-wrapper{min-height:100%;top:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.12.0/lodash.js"></script>

Update

You can mutate the object itself by creating a function that recursively traverses the object with each() and settles the removal by unset().

function omitByRecursivelyInPlace(value, iteratee) {

  _.each(value, (v, k) => {

    if(iteratee(v, k)) {
      _.unset(value, k); 
    } else if(_.isObject(v)) {
      omitByRecursivelyInPlace(v, iteratee);  
    }

  });

  return value;

}

function Cons(obj){_.extend(this, obj)}

var result = omitByRecursivelyInPlace(instance, (v, k) => k[0] === '_');

function omitByRecursivelyInPlace(value, iteratee) {
  
  _.each(value, (v, k) => {
    
    if(iteratee(v, k)) {
      _.unset(value, k); 
    } else if(_.isObject(v)) {
      omitByRecursivelyInPlace(v, iteratee);  
    }
    
  });
  
  return value;
  
}

function Cons(obj){_.extend(this, obj)}

var instance = new Cons({
  key1 : 'value1', 
  key2 : {
    key21 : 'value21', 
    _key22: undefined
  }, 
  key3: undefined,
  _key4 : undefined,
  key5: [
    {
      _key: 'value xx',
      key7: 'value zz',
      _key8: 'value aa'
    }
  ]
});

var result = omitByRecursivelyInPlace(instance, (v, k) => k[0] === '_');

console.log(result instanceof Cons);
console.log(result);
.as-console-wrapper{min-height:100%;top:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.12.0/lodash.js"></script>
like image 143
ryeballar Avatar answered Sep 23 '22 07:09

ryeballar


You can use the rundef package.

By default, it will replace all top-level properties with values set to undefined. However it supports the following options:

  • mutate - set this to false to return the same object that you have provided; this will ensure the constructor is not changed
  • recursive - set this to true to recursively process your object

Therefore, for your use case, you can run:

rundef(object, false, true)
like image 40
d4nyll Avatar answered Sep 22 '22 07:09

d4nyll