2013-11-20 1 views
0

Я использую метод jQuery $ .extend для рекурсивного слияния двух объектов, но он не работает так, как я ожидал. (Помимо этого: эти объектные литералы находятся в формате, который требуется CKEditor для настройки его панели инструментов.)Почему jQuery Extend не рекурсивно копирует эти два объектных литерала?

Ожидаемый результат: Максимизировать, ShowBlocks и источник.

Актуальный результат: Maximize, ShowBlocks.

var obj1 = [ 
    { name: 'styles', items: ['Format', 'Font', 'FontSize'] }, 
    { name: 'colors', items: ['TextColor', 'BGColor'] }, 
    { name: 'tools', items: ['Maximize', 'ShowBlocks'] }, 
]; 
var obj2 = [ 
    { name: 'tools', items: ['Source'] } 
]; 

var recursiveFail = $.extend(true, {}, obj1, obj2); 

// Test result here.... 
alert(recursiveFail[2].items); 

Вопрос: Почему не вариант 'Source' добавляется в?

ответ

2

$.extend не работает так: он копирует свойства объектов из одного объекта в другой. Он не может идентифицировать такие вещи, как «Я вижу, что« имя »одинаково в этих объектах этого массива, поэтому я знаю, чтобы объединить массивы« элементов ».

Возможно, вам придется написать свой собственный цикл для увеличения obj1 с помощью obj2.

// Add 'Source' command to the tools group 
for (var i = 0; i < obj1.length; i++) { 
    if (obj1[i].name === 'tools') { 
     obj1[i].items.push('Source'); 
     break; 
    } 
} 
1

$.extend не предназначен для использования таким образом.

Однако вы можете написать свою собственную функцию расширения/слияния. Ниже приведен пример функции, которая объединит все объекты, считающиеся равными (в зависимости от значения конкретного ключа) от нескольких предоставленных массивов вместе.

Следующий алгоритм слияния переопределяет примитивные значения и объединит массивы. Исходные массивы и их объекты не изменяются.

Возможно, это будет излишним, если вам нужно сделать это один раз, однако это пример того, как вы можете реализовать свой собственный инкапсулированный алгоритм слияния.

function mergeOnKey(mergeKey) { 
    var mergedObjectsIndex = {}, 
     mergedObjects = [], 
     arrays = Array.prototype.slice.call(arguments, 1), 
     i = 0, 
     arraysLen = arrays.length, 
     x, arrLen, arr, obj, k, 
     mergeVal, mergedObjIndex, 
     mergedObj, mergedVal; 

    for (; i < arraysLen ; i++) { 
     arr = arrays[i]; 

     for (x = 0, arrLen = arr.length; x < arrLen; x++) { 
      obj = arr[x]; 
      mergeVal = obj[mergeKey]; 
      mergedObjIndex = mergedObjectsIndex[mergeVal]; 

      if (typeof mergedObjIndex === 'undefined') { 
       mergedObjectsIndex[mergeVal] = mergedObjects.push($.extend({}, obj)) - 1; 
       continue; 
      } 

      mergedObj = mergedObjects[mergedObjIndex]; 

      for (k in obj) { 
       if (!obj.hasOwnProperty(k) || k === mergeKey) continue; 

       if (Array.isArray(mergedVal = mergedObj[k])) mergedObj[k] = mergedVal.concat(obj[k]); 
       else mergedObj[k] = obj[k]; 
      } 
     } 
    } 

    return mergedObjects; 
} 

Вы могли бы использовать его как:

var obj1 = [ 
    { name: 'styles', items: ['Format', 'Font', 'FontSize'] }, 
    { name: 'colors', items: ['TextColor', 'BGColor'] }, 
    { name: 'tools', items: ['Maximize', 'ShowBlocks'] } 
]; 

var obj2 = [ 
    { name: 'tools', items: ['Source'], test: 'test' } 
]; 

var merged = mergeOnKey('name', obj1, obj2); 

console.log(merged[2].items); //["Maximize", "ShowBlocks", "Source"]