我编写了一个 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 库存功能来实现这一点?
据我所知
_.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>
这可以通过使用递归 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.entries 和 reduce:
执行此操作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
不充分等,您还可以扩展对对象的检查。
还有另一种选择,使用 DeepDash,它是一个独立的补充库,提供 Lodash 函数的递归版本。
一旦 DeepDash 与 Lodash (
deepdash(_)
) 混合在一起,你就可以编写一个像这样的 prune
函数:
const prune = obj => _.filterDeep(obj, (v) => !_.isUndefined(v))
我喜欢 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>