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 add
Disclaimer: I have no idea what lodash supports as built-in functions, but this is very easy to implement with vanilla javascript.
Start with a generic function for filtering your object's keys
// filter obj using function f
// this works just like Array.prototype.filter, except on objects
// f receives (value, key, obj) for each object key
// if f returns true, the key:value appears in the result
// if f returns false, the key:value is skipped
const filterObject = f=> obj=>
Object.keys(obj).reduce((res,k)=>
f(obj[k], k, obj) ? Object.assign(res, {[k]: obj[k]}) : res
, {});
Then a function that filters based on your specific behavior
// filter out keys starting with `_` that have null or undefined values
const filterBadKeys = filterObject((v,k)=> /^[^_]/.test(k) || v !== null && v !== undefined);
Then call it on an object
filterBadKeys({a: null, _b: null, _c: undefined, z: 1});
//=> { a: null, z: 1 }
This can be easily integrated into your constructor now
function Cons(obj) {
_.extend(this, filterBadKeys(obj));
// ...
}
EDIT:
On second thought, instead of butchering a perfectly good function with implicit deep recursion, you could abstract out the generic operations and define a specific "deep" filtering function
const reduceObject = f=> init=> obj=>
Object.keys(obj).reduce((res,k)=> f(res, obj[k], k, obj), init);
// shallow filter
const filterObject = f=>
reduceObject ((res, v, k, obj)=> f(v, k, obj) ? Object.assign(res, {[k]: v}) : res) ({});
// deep filter
const deepFilterObject = f=>
reduceObject ((res, v, k, obj)=> {
if (f(v, k, obj))
if (v && v.constructor === Object)
return Object.assign(res, {[k]: deepFilterObject (f) (v)});
else
return Object.assign(res, {[k]: v});
else
return res;
}) ({});
const filterBadKeys = deepFilterObject((v,k)=> /^[^_]/.test(k) || v !== null && v !== undefined);
filterBadKeys({a: null, _b: null, _c: undefined, _d: { e: 1, _f: null }, z: 2});
//=> { a: null, _d: { e: 1 }, z: 2 }
Integration into your constructor stays the same
function Cons(obj) {
_.extend(this, filterBadKeys(obj));
// ...
}