更新:最后我得到了一个有效的解决方案https://jsfiddle.net/olehmelnyk/oz7ez881/20/,但它看起来过于复杂,需要重构;
处理元标记解析器。 我正在寻找一个简单的JavaScript解决方案来扩展/深度合并两个对象,没有任何覆盖。我希望将目标中的原始值和源中的新值存储为数组,而不是覆盖。
输入 - 一次只有一个对象,在这种情况下,每个对象一次只包含一个值,但是这个值可以处于任何深层次,如下所示:
let obj1 = {
og: {
image: {
src: 'http://'
}
}
};
let obj2 = {
og: {
image: {
width: 640
}
}
};
let obj3 = {
og: {
image: {
height: 320
}
}
};
let obj4 = {
og: {
image: {
src: 'http://'
}
}
};
let obj5 = {
og: {
image: {
src: 'http://'
}
}
};
let obj6 = {
og: {
image: {
width: 640
}
}
};
期望输出应该是这样的:
{
og: {
image: [
{src: '...', width: 640, height: 320},
{src: '...'},
{src: '...', width: 640}
]
}
}
可能的伪代码(我不确定正确的算法):
- 1.检查我们的目标中是否存在与来源类似的内容
- 1.1如果不是 - 我们只是将源添加到目标
- 1.2否则 - 我们检查是否添加了唯一的源值
- 1.2.1如果是,我们可以将源与目标合并
- 1.2.2否则我们创建一个数组,其中包含目标的原始值和源
答案 0 :(得分:0)
冬青牛,我做到了! 现在它按预期工作,但代码看起来过于复杂,因此需要重构。
function objectExtend(target, source) {
let flatSource = flattenObject(source); // {og.image.src: 'http://'}
let flatSourceKey = Object.keys(flatSource)[0]; // og.image.src
let sourceKeys = flatSourceKey.split('.'); // ['og', 'image', 'src']
let sourceKey = sourceKeys.slice(-1); // 'src'
let sourceValue = flatSource[flatSourceKey]; // 'http://'
let sourceKeyValue = {[sourceKey]: sourceValue}; // {src: 'http://'}
let sourcePath = sourceKeys.slice(0, -1).join('.'); // og.image
let flatTarget = flattenObject(target); // target with array of all key-values flattened
let flatTargetKeys = Object.keys(flatTarget); // array of all flattened target keys
let targetValue = flatTarget[flatSourceKey]; // target value (if any)
let targetValueIsArray = Array.isArray(flatTarget[sourcePath]);
let targetLastValue = targetValue;
let targetArray;
if(targetValueIsArray){
targetArray = flatTarget[sourcePath];
targetLastValue = targetArray[targetArray.length - 1];
}
let targetKey;
try{
targetKey = eval(`target.${sourcePath}`);
}catch(e){/*we don't care*/}
if(!flatTargetKeys.includes(flatSourceKey) && !targetValueIsArray){
// because source will contain og.image.width, but after creating an array width will be in array, so og.image.width will look like unique key
mergeDeep(target, source);
}else if(flatTargetKeys.includes(flatSourceKey) && !targetValueIsArray){
// create array with 2 values - current object[key] and source object[key] - we put object with src/width/heigth object
mergeDeep(target, unflattenObject(sourcePath, [targetKey, sourceKeyValue]));
}else if(targetValueIsArray){
targetLastValue.hasOwnProperty(sourceKey)
? targetArray.push(sourceKeyValue) // create new array value array.push
: targetArray.push(Object.assign(targetArray.pop(), sourceKeyValue)); // merge with last array value Object.assign()
targetKey = targetArray;
}
}