我发表评论的想法是其他人会发表更严肃的答案,但由于没有人出现,我想我会描述你如何认真地去做。
首先,您必须知道如何将一个对象合并到另一个对象中。这不是太难,但你必须知道如何使用for-in,这不是经常教的,而且包含hasOwnProperty检查通常是个好主意,它甚至不经常教:
function mergeObjectInto(source, target) {
for(var property in source) {
if(Object.prototype.hasOwnProperty.call(source, property)) {
target[property] = source[property];
}
}
}
本质上,这会枚举源的所有属性。如果该属性是对象的自己的属性——也就是说,它不是从其原型继承的东西——我们将该属性复制到目标。
现在,要对您想要执行的操作进行建模,我们可以将其分解为更简单的操作:给定一个现有数组,将另一个对象放入该数组中,并在必要时合并。一个简单的实现可能如下所示:
function mergeObjectIntoArray(existingArray, newObject) {
// Search for an already-existing object in the array that shares the same
// value for the `date' property.
var correspondingExistingObject = null;
for(var index = 0, length = existingArray.length; index < length; index++) {
if(existingArray[index].date === newObject.date) {
correspondingExistingObject = existingArray[index];
break;
}
}
if(correspondingExistingObject !== null) {
// If we found an existing object that corresponds to our new object, just
// merge any new properties in rather than adding a new item to the array.
mergeObjectInto(newObject, correspondingExistingObject);
}else{
// Otherwise, bite the bullet and add the new object since there's nothing
// we can usefully merge into.
existingArray.push(newObject);
}
}
然后您可以通过在循环中调用此函数来实现您想要的那种合并操作。但是如果你算出来,那将有二次时间,如果这必须处理大量数据项,这将是一个问题。碰巧,有一种方法可以解决它。如果我们将项目排序为一个由date 属性作为键的类似哈希表的结构,我们可以在常数时间内检查我们是否有一个具有该日期的对象,如果有,则合并到其中;否则,添加它。这导致整个算法的线性时间非常合理。
一个复杂的问题是,直到最近使用 ECMAScript 6,JavaScript 还没有真正拥有真正的“哈希表”。我们拥有的最接近的东西是对象,它只能有字符串键。这对我们有用,但我们确实需要谨慎行事:无论好坏,浏览器供应商都创建了一些具有特殊意义的属性名称,例如__proto__,我们真的不想踩到它们,所以我们'将为我们的键添加一些字符,以防止与内置名称发生任何冲突。为此,我选择了#。 (# 是一个哈希,它是一个哈希表。)
在代码中,这是如何实现的,这次函数采用整个项目数组并合并所有具有重复 date 属性值的对象:
function mergeDuplicateObjectsInArray(array) {
var result = [];
var objectsByDate = {};
for(var index = 0, length = array.length; index < length; index++) {
var object = array[index];
var hashKey = '#' + object.date;
var mergeTarget;
if(Object.prototype.hasOwnProperty.call(objectsByDate, hashKey)) {
// Already have an object by that date; we ought to merge into that.
mergeObjectInto(object, objectsByDate[object.date]);
}else{
// No object by that date yet; we'll be the first.
result.push(object);
objectsByDate[object.date] = object;
}
}
return result;
}
这仍然遗漏了最后一件事:它只是合并单个数组中的对象,而不是两个不同的数组。但是如果你用两个数组的对象创建了一个数组,它会做你想做的事,例如myVar1.concat(myVar2)。在任何情况下,您还可以修改其中的for 循环以循环遍历数组数组,然后循环遍历这些数组中的对象,这就是我打高尔夫球的版本所做的。 Golfed 版本的另一个区别是 Golfed 版本避免修改原始数组或对象,这将是对未混淆版本的相对简单的修改:制作副本,只需合并到一个空对象中。
希望这可以解决问题。