2012-11-07 72 views
7

我在想這一定是一個常見的問題,但似乎無法找到解決方案。 使用JSON配置文件來擴展包含對象和數組的jQuery對象。修改jQuery擴展到推送對象內的數組項目,但擴展其他對象

對於對象和簡單的屬性,我想覆蓋(因爲extend很好)。

對於數組,可能存在或不存在現有項目。

目前數組只是覆蓋的第一要素

var sourceObj = {propterty:"change Me",anArray:[{name:"first"},{name:"second"}]}, 
    configJSON = '{"propterty":"New Val","anArray":[{"name":"third"}]}', 
    configObj = JSON.parse(configJSON); 

$.extend(true,sourceObj,configObj); 

http://jsfiddle.net/PmuwV/

這將返回:

{propterty:"New Val" , anArray:[{name:"third"},{name:"second"}} 

我可以代替得到:

{propterty:"New Val",anArray:[{name:"first"},{name:"second"},{name:"third"}]} 

,同時還允許更新「第一」和「第二」對象?

"anArray":[{"name":"second","newProp":"add newProp to second"}] 

可以/應該extend進行修改,以比較陣列項目,延長或新增一些規則或設置屬性值,如「名」?

感謝您的任何建議或指針。

+0

這似乎是最接近我發現可能做到這一點 - http://stackoverflow.com/questions/3748697/jquery-extend-arra y-of-objects –

+0

'$ .extend'的正常使用用於將用戶提供的選項與默認值合併。在這種情況下,通常最好使用新屬性來完全替換原始對象中的一個;追加數組屬性不符合它通常使用的方式。你需要做什麼? – Barmar

+0

@Barmar這是一個用例,但還有很多其他...包括將新的函數/方法擴展到jQuery對象本身 – charlietfl

回答

2

我用這個解決方案從How can I merge properties of two JavaScript objects dynamically?還修改http://jsfiddle.net/PmuwV/2/JavaScript equivalent of jQuery's extend method

需要isDOMNode() 我只是一個jQuery合併加入(是的,我覺得髒太)在其中重複將需要清理陣列合併後。 擴展的Jquery源代碼做了一些非常相似的事情,但我發現它更具可讀性。

function mergeRecursive() { 
    // _mergeRecursive does the actual job with two arguments. 
    var _mergeRecursive = function (dst, src) { 
    if (isDOMNode(src) || typeof src!=='object' || src===null) { 
     return dst; 
    } 

    for (var p in src) { 

//my added bit here - [SB] 
     if ($.isArray(src[p])){ 
      $.merge(dst[p],src[p]); 
      var dupes = {}, 
       singles = []; 
      $.each( dst[p], function(i, el) { 
      if ((dupes[el.name] > -1) && (el.name)) { 
       $.extend(singles[dupes[el.name]],el); 
      }else{ 
        if (el.name){ 
        dupes[el.name] = i; 
        } 
       singles.push(el); 
      } 
     }); 
     dst[p] = singles; 
     } 
     continue;   
     } 
//the rest is original - [SB] 

     if(!src.hasOwnProperty(p)) continue; 
     if (src[p]===undefined) continue; 
     if (typeof src[p]!=='object' || src[p]===null) { 
     dst[p] = src[p]; 
     } else if (typeof dst[p]!=='object' || dst[p]===null) { 
     dst[p] = _mergeRecursive(src[p].constructor===Array ? [] : {}, src[p]); 
     } else {    
     _mergeRecursive(dst[p], src[p]); 
     } 
    } 
    return dst; 
    } 

    // Loop through arguments and merge them into the first argument. 
    var out = arguments[0]; 
    if (typeof out!=='object' || out===null) return out; 
    for (var i=1, il=arguments.length; i<il; i++) { 
    _mergeRecursive(out, arguments[i]); 
    } 
    return out; 
} 
+0

更新在http://jsfiddle.net/PmuwV/5/將重複的數組對象與特定的匹配屬性合併 –

+0

需要類似的東西,所以我修改了你的一些使用下劃線:http://codepen.io/clouddueling/pen/nFDCH –

+1

不錯的解決方案,但我發現在上面的代碼中找到2個錯誤,所以我添加了一個「答案」與更新後的代碼。 – user3708842

2

這是一個與lodash library

var targetObj = { 
    customerId: "123", 
    orders: [ 
     "item1", "item2" 
    ] 
}; 

var otherObj = { 
    customerName: "John", 
    orders: [ 
     "item3", "item4" 
    ] 
}; 

_.merge(targetObj, otherObj, function (a, b) { 
    if (_.isArray(a)) { 
    return a.concat(b); 
    } 
}); 

結果比較直接的方式是:

targetObj = { 
    customerId: "123", 
    customerName: "John", 
    orders: [ 
     "item1", "item2", "item3", "item4" 
    ]  
} 
+0

謝謝!這工作完美! – swrobel

+1

對於任何人在2016年或之後閱讀此文,似乎今天上面例子的正確lodash函數是__mergeWith()' – AsGoodAsItGets

0

我知道這是老了,但我發現這個職位,並使用上述史蒂夫黑人的代碼,但發現了一些錯誤:

  1. 在isArray部分的'continue'之前有一個額外的'}'。
  2. 如果源沒有數組的話,那將拋出一個 錯誤,所以我說這個到IsArray的部分

    if (!dst[p]) { 
        dst[p] = src[p]; 
        continue; 
    } 
    

所以最終代碼如下所示:

function isDOMNode(v) { 
    if (v===null) return false; 
    if (typeof v!=='object') return false; 
    if (!('nodeName' in v)) return false; 
    var nn = v.nodeName; 
    try { 
     v.nodeName = 'is readonly?'; 
    } catch (e) { 
     return true; 
    } 
    if (v.nodeName===nn) return true; 
    v.nodeName = nn; 
    return false; 
} 

function mergeRecursive() { 
    // _mergeRecursive does the actual job with two arguments. 
    var _mergeRecursive = function (dst, src) { 
     if (isDOMNode(src) || typeof src!=='object' || src===null) { 
      return dst; 
     } 

     for (var p in src) { 
      if ($.isArray(src[p])) { 
       if (!dst[p]) { 
        dst[p] = src[p]; 
        continue; 
       } 
       $.merge(dst[p],src[p]); 
       var dupes = {}, singles = []; 
       $.each(dst[p], function(i, el) { 
        if ((dupes[el.name] > -1) && (el.name)) { 
         $.extend(singles[dupes[el.name]],el); 
        } else { 
         if (el.name) { 
          dupes[el.name] = i; 
         } 
        singles.push(el); 
        } 
       }); 
       dst[p] = singles; 
       continue;   
      } 

      if (!src.hasOwnProperty(p)) continue; 
      if (src[p]===undefined)  continue; 
      if (typeof src[p]!=='object' || src[p]===null) { 
       dst[p] = src[p]; 
      } else if (typeof dst[p]!=='object' || dst[p]===null) { 
       dst[p] = _mergeRecursive(src[p].constructor===Array ? [] : {}, src[p]); 
      } else {    
       _mergeRecursive(dst[p], src[p]); 
      } 
     } 
     return dst; 
    } 

    // Loop through arguments and merge them into the first argument. 
    var out = arguments[0]; 
    if (typeof out!=='object' || out===null) return out; 
    for (var i=1, il=arguments.length; i<il; i++) { 
     _mergeRecursive(out, arguments[i]); 
    } 
    return out; 
} 
0
<html> 
<head> 
<script type="text/javascript" src="./jquery-2.1.3.js"></script> <!-- for json extend/merge --> 
<script type="text/javascript" src="./jQuery.extendext.min.js"></script> <!-- for json extend/merge - with array extend (instead of array overwrite) - https://github.com/mistic100/jQuery.extendext --> 

<script> 
var jsonResult = {}; 
var json1 = 
{ 
    "properties": 
    { 
     "street_address": { "type": "string" }, 
     "city": { "type": "string" }, 
     "state": { "type": "string" } 
    }, 
    "required": ["street_address", "city", "state"] 
}; 
var json2 = 
{ 
    "properties": 
    { 
     "country": { "type": "string" }, 
     "country-dial-code": { "type": "integer" }, 
     "country-short": { "type": "string" } 
    }, 
    "required": ["country", "country-dial-code", "country-short"] 
}; 
$.extendext(true, 'extend', jsonResult, json1, json2); 
console.log(JSON.stringify(jsonResult)); 
/* output -> 
{ "properties": 
    { "street_address":{"type":"string"}, 
     "city":{"type":"string"}, 
     "state":{"type":"string"}, 
     "country":{"type":"string"}, 
     "country-dial-code":{"type":"integer"}, 
     "country-short":{"type":"string"} 
    }, 
    "required":["street_address","city","state","country","country-dial-code","country-short"] 
} 
*/ 
</script> 
</head> 
<body> 
</body> 
</html> 
+0

https://github.com/mistic100/jQuery.extendext –

+0

鍵「F12」查看控制檯 –