【问题标题】:Lodash cloneDeepWith to omit undefinedLodash cloneDeepWith 省略 undefined
【发布时间】:2018-10-23 18:28:38
【问题描述】:

我编写了一个 customozer 函数来省略 cloneDeepWith 对象的未定义值。然而,在不可变的回报上,它并没有递归地挖掘。这是我的代码:

import { cloneDeepWith, pickBy, omit } from 'lodash';

const obj = {
  a0: true,
  b0: true,
  c0: undefined,
  obj1: {
    a1: true,
    b1: true,
    c1: undefined
  }
};

cloneDeepWith(obj, value => {
    const objWithUndefinedValue = pickBy(obj, (value) => value === undefined);
    const keysWithUndefinedValue = Object.keys(objWithUndefinedValue);
    return omit(obj, keysWithUndefinedValue);
});

但是它在第一次返回后不会递归。是否可以使用 lodash 库存功能来实现这一点?

【问题讨论】:

    标签: javascript lodash


    【解决方案1】:

    据我所知_.cloneDeepWith() 定制器有点误导。定制器应该只处理非对象值。如果它处理对象值,它也应该自己继续递归。例如,您可以看到在调用自定义程序时,克隆由value.cloneNode(true) 处理。如您所见,控制台中仅出现body

    const { cloneDeepWith, isObject } = _;
    
    function customizer(value) {
      console.log(value);
      if (_.isElement(value)) {
        return value.cloneNode(true);
      }
    }
     
    var el = _.cloneDeepWith(document.body, customizer);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

    但是,如果您只是自定义非对象值,并为对象值返回 undefined,这会提示处理它们的方法(记录在 cloneDeep 中),它会迭代所有内容:

    const { cloneDeepWith, isObject, isUndefined } = _;
    
    const obj = {
      a0: true,
      b0: true,
      c0: undefined,
      obj1: {
        a1: true,
        b1: true,
        c1: undefined
      }
    };
    
    const result = cloneDeepWith(obj, v => {
      console.log(v);
      
      return isObject(v) ? undefined : 'custom value';
    });
    
    console.log(result);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

    为了解决你的问题,你可以递归地使用_.transform()来取所有不是undefined的值:

    const { transform, isObject, isUndefined } = _;
    
    const obj = {
      a0: true,
      b0: true,
      c0: undefined,
      obj1: {
        a1: true,
        b1: true,
        c1: undefined
      }
    };
    
    const cloneDeepWithoutUndefined = (obj) =>
      transform(obj, (r, v, k) => {
        if(isUndefined(v)) return;
        r[k] = isObject(v) ? cloneDeepWithoutUndefined(v) : v;
      });
      
    const result = cloneDeepWithoutUndefined(obj);
    
    console.log(result);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

    【讨论】:

    • 欢迎 :) 我也对这种行为感到困惑。
    【解决方案2】:

    这可以通过使用递归 lodash transform 方法来解决:

    const obj = { a0: true, b0: true, c0: undefined, obj1: { a1: true, b1: true, c1: undefined } };
    
    const cloneMe = (obj) => _.transform(obj, (r, v, k) => 
      _.isUndefined(v) ? null : _.isObject(v) ? r[k] = cloneMe(v) : r[k] = v, {})
    
    console.log(cloneMe(obj))
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

    您也可以在 ES6 中仅通过 Object.entriesreduce 执行此操作:

    const obj = { a0: true, b0: true, c0: undefined, obj1: { a1: true, b1: true, c1: undefined } };
    
    const cloneMe = (obj) => {
       return Object.entries(obj).filter(([k,v]) => 
          v != undefined).reduce((r,[k,v]) => {
            r[k] = (v instanceof Object) ? cloneMe(v) : v
            return r
       },{})
    }
    
    console.log(cloneMe(obj))

    如果instance of Object 不够等,您可以额外扩展对象检查。

    【讨论】:

    • 这太酷了,感谢 es6 和 lodash 方法!
    【解决方案3】:

    还有另一种使用 DeepDash 的替代方法,它是一个独立的补充库,提供 Lodash 函数的递归版本。

    DeepDash 与 Lodash (deepdash(_)) 混合后,您可以像这样编写 prune 函数:

    const prune = obj => _.filterDeep(obj, (v) => !_.isUndefined(v))
    

    【讨论】:

    • 这非常有趣,谢谢!绝对是最简单的解决方案!
    • 是的!这些库中有很多出色的工作,并且经过了很好的测试,可以处理边缘情况,如果他们自己推出,可能会错过这些情况。我总是更喜欢库,即使它看起来像“只有几行代码”。
    猜你喜欢
    • 2020-04-14
    • 2016-01-25
    • 1970-01-01
    • 1970-01-01
    • 2018-08-24
    • 2018-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多