Lodash cloneDeepWith 省略 undefined

问题描述 投票:0回答:4

我编写了一个 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
4个回答
19
投票

据我所知

_.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>


3
投票

这可以通过使用递归 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
不充分等,您还可以扩展对对象的检查。


2
投票

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

一旦 DeepDash 与 Lodash (

deepdash(_)
) 混合在一起,你就可以编写一个像这样的
prune
函数:

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

0
投票

我喜欢 Ori Drori 的解决方案。

改进的解决方案

递归地获取所有未定义的值

包括数组中的值:

const { transform, isArray, isObject, isUndefined } = _;

const obj = {
  a0: true,
  b0: true,
  c0: undefined,
  obj1: {
    a1: true,
    b1: true,
    c1: undefined
  },
  arr: [undefined, 1, true, undefined, { foo: "bar" }]
};

const cloneDeepWithoutUndefined = (obj) =>
  transform(
    isArray(obj) ? obj.filter((item) => item !== undefined) : 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>

© www.soinside.com 2019 - 2025. All rights reserved.