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

前端 未结 4 2430
醉酒成梦
醉酒成梦 2021-02-20 14:01

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

4条回答
  •  伪装坚强ぢ
    2021-02-20 14:21

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

提交回复
热议问题