我需要做一些像_.assign这样的事情,但前提是目标对象已经分配了属性。可以想象它就像源对象可能有一些属性要贡献,但也有一些我不想混合的属性。
我还没有使用_.assign的回调机制,但尝试了以下内容。它“工作”,但它仍然将属性分配给dest对象(未定义)。我根本不希望它分配。
_.assign(options, defaults, initial, function (destVal, sourceVal) {
return typeof destVal == 'undefined' ? undefined : sourceVal;
});
我编写了以下函数来执行此操作,但想知道lodash是否已经有更好的烘焙内容。
function softMerge (dest, source) {
return Object.keys(dest).reduce(function (dest, key) {
var sourceVal = source[key];
if (!_.isUndefined(sourceVal)) {
dest[key] = sourceVal;
}
return dest;
}, dest);
}
答案 0 :(得分:16)
你可以只从第一个对象中取出钥匙
var firstKeys = _.keys(options);
然后从第二个对象中获取一个子集对象,仅获取第一个对象上存在的那些键:
var newDefaults = _.pick(defaults, firstKeys);
然后使用该新对象作为_.assign
的参数:
_.assign(options, newDefaults);
或者在一行中:
_.assign(options, _.pick(defaults, _.keys(options)));
我在这里测试时似乎工作了:http://jsbin.com/yiyerosabi/1/edit?js,console
答案 1 :(得分:0)
这是一个不可变的深层版本,我称之为“合并,保留形状”,在使用lodash的TypeScript中:
function _mergeKeepShapeArray(dest: Array<any>, source: Array<any>) {
if (source.length != dest.length) {
return dest;
}
let ret = [];
dest.forEach((v, i) => {
ret[i] = _mergeKeepShape(v, source[i]);
});
return ret;
}
function _mergeKeepShapeObject(dest: Object, source: Object) {
let ret = {};
Object.keys(dest).forEach((key) => {
let sourceValue = source[key];
if (typeof sourceValue !== "undefined") {
ret[key] = _mergeKeepShape(dest[key], sourceValue);
} else {
ret[key] = dest[key];
}
});
return ret;
}
function _mergeKeepShape(dest, source) {
// else if order matters here, because _.isObject is true for arrays also
if (_.isArray(dest)) {
if (!_.isArray(source)) {
return dest;
}
return _mergeKeepShapeArray(dest, source);
} else if (_.isObject(source)) {
if (!_.isObject(source)) {
return dest;
}
return _mergeKeepShapeObject(dest, source);
} else {
return source;
}
}
/**
* Immutable merge that retains the shape of the `existingValue`
*/
export const mergeKeepShape = <T>(existingValue: T, extendingValue): T => {
return _mergeKeepShape(existingValue, extendingValue);
}
一个简单的测试,看看我如何看待这样的合并应该有效:
let newObject = mergeKeepShape(
{
a : 5,
// b is not here
c : 33,
d : {
e : 5,
// f is not here
g : [1,1,1],
h : [2,2,2],
i : [4,4,4],
}
},
{
a : 123,
b : 444,
// c is not here
d : {
e : 321,
f : 432,
// g is not here
h : [3,3,3],
i : [1,2],
}
}
);
expect(newObject).toEqual({
a : 123,
// b is not here
c : 33,
d : {
e : 321,
// f is not here,
g : [1,1,1],
h : [3,3,3],
i : [4,4,4]
}
});
我在测试中使用了无缝不可变的自己,但是没有必要把它放在这个答案中。
我将此放在公共领域。
答案 2 :(得分:0)
实现此目标的另一种方法是将_.mapObject
与_.has
_.mapObject(object1, function(v, k) {
return _.has(object2, k) ? object2[k] : v;
});
说明:
object1
_.mapObject
的所有键/值对
_.has
,检查k
中是否还存在属性名称object2
。object2
的{{1}}的值复制回k
,否则,只返回object1(object1
)的现有值。 答案 3 :(得分:0)
在@svarog的回答之后,我想到了这个(lodash版本4.17.15):
const mergeExistingProps = (target, source) => _.mapValues(target, (value, prop) => _.get(source, prop, value));