Lodash cloneDeepWith忽略未定义

时间:2018-10-23 18:28:39

标签: javascript lodash

我编写了一个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的股票功能来完成此任务吗?

3 个答案:

答案 0 :(得分:5)

据我所知_.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>

答案 1 :(得分:1)

可以通过以下方式使用递归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>

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

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不足等,您还可以扩展对对象的检查。

答案 2 :(得分:1)

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

将DeepDash与Lodash(deepdash(_))混合后,您可以编写一个prune函数,如下所示:

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