Javascript 修改jQuery extend以在对象内推送数组项,但扩展其他对象

Javascript 修改jQuery extend以在对象内推送数组项,但扩展其他对象,javascript,jquery,extend,Javascript,Jquery,Extend,我想这一定是个常见的问题,但似乎找不到解决办法。 使用JSON配置文件扩展包含对象和数组的jQuery对象 对于对象和简单属性,我想覆盖(正如extend所做的那样) 对于阵列,可能存在或不存在项 当前,数组只覆盖第一个元素 var sourceObj = {propterty:"change Me",anArray:[{name:"first"},{name:"second"}]}, configJSON = '{"propterty":"New Val","anArray":[{"n

我想这一定是个常见的问题,但似乎找不到解决办法。 使用JSON配置文件扩展包含对象和数组的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);

这将返回:

{propterty:"New Val" , anArray:[{name:"third"},{name:"second"}}
我可以得到:

{propterty:"New Val",anArray:[{name:"first"},{name:"second"},{name:"third"}]}
同时还允许更新“第一”和“第二”对象

是否可以/应该修改
extend
以比较数组项,并根据某些规则或设置属性值(如“name”)进行扩展或添加

谢谢你的建议和指点。

我使用了这个解决方案 修改自也修改自

需要isDOMNode() 我刚刚在数组上添加了jquery合并(是的,我也觉得脏了),其中的重复项在合并后需要清理。 extend的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;
}
函数mergeRecursive(){
//\u mergeRecursive使用两个参数执行实际工作。
var _mergeRecursive=函数(dst,src){
if(isDOMNode(src)| | typeof src!='object'| | src===null){
返回dst;
}
用于(src中的var p){
//我在这里加了一点-[SB]
如果($.isArray(src[p])){
$.merge(dst[p],src[p]);
var dupes={},
单打=[];
$。每个(dst[p],功能(i,el){
如果((重复[el.name]>-1)和&(el.name)){
$.extend(单件[dupes[el.name]],el);
}否则{
如果(el.name){
重复[el.name]=i;
}
单打。推(el);
}
});
dst[p]=单打;
}
继续;
}
//其余的是原创的-[SB]
如果(!src.hasOwnProperty(p))继续;
如果(src[p]==未定义)继续;
if(类型src[p]!='object'| | src[p]==null){
dst[p]=src[p];
}else if(dst[p]!='object'| | dst[p]==null的类型){
dst[p]=_mergeRecursive(src[p]。构造函数===数组?[]:{},src[p]);
}否则{
_合并递归(dst[p],src[p]);
}
}
返回dst;
}
//循环遍历参数并将它们合并到第一个参数中。
var out=参数[0];
如果(typeof out!=“object”| out==null)返回out;

对于(var i=1,il=arguments.length;i来说,使用

结果是:

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

我知道这很旧,但我找到了这篇文章并使用了上面的Steve Blacks代码,但发现了一些bug:

  • 在isArray部分的“continue”之前还有一个额外的“}”
  • 如果源根本没有数组,它将抛出 错误,所以我将其添加到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;
    }
    
    功能isDOMNode(v){
    如果(v==null)返回false;
    if(typeof v!=“object”)返回false;
    如果(!('nodeName'在v中))返回false;
    var nn=v.nodeName;
    试一试{
    v、 nodeName='是否为只读?';
    }捕获(e){
    返回true;
    }
    if(v.nodeName==nn)返回true;
    v、 nodeName=nn;
    返回false;
    }
    函数mergeRecursive(){
    //\u mergeRecursive使用两个参数执行实际工作。
    var _mergeRecursive=函数(dst,src){
    if(isDOMNode(src)| | typeof src!='object'| | src===null){
    返回dst;
    }
    用于(src中的var p){
    如果($.isArray(src[p])){
    如果(!dst[p]){
    dst[p]=src[p];
    继续;
    }
    $.merge(dst[p],src[p]);
    var dupes={},singles=[];
    $。每个(dst[p],功能(i,el){
    如果((重复[el.name]>-1)和&(el.name)){
    $.extend(单件[dupes[el.name]],el);
    }否则{
    如果(el.name){
    重复[el.name]=i;
    }
    单打。推(el);
    }
    });
    dst[p]=单打;
    继续;
    }
    如果(!src.hasOwnProperty(p))继续;
    如果(src[p]==未定义)继续;
    if(类型src[p]!='object'| | src[p]==null){
    dst[p]=src[p];
    }else if(dst[p]!='object'| | dst[p]==null的类型){
    dst[p]=_mergeRecursive(src[p]。构造函数===数组?[]:{},src[p]);
    }否则{
    _合并递归(dst[p],src[p]);
    }
    }
    返回dst;
    }
    //循环遍历参数并将它们合并到第一个参数中。
    var out=参数[0];
    如果(typeof out!=“object”| out==null)返回out;
    对于(var i=1,il=arguments.length;i
    
    var jsonResult={};
    var json1=
    {
    “财产”:
    {
    “街道地址”:{“类型”:“字符串”},
    “城市”:{“类型”:“字符串”},
    “状态”:{“类型”:“字符串”}
    },
    “必需”:[“街道地址”、“城市”、“州”]
    };
    var json2=
    {
    “财产”:
    {
    “国家”:{“类型”:“字符串”},
    “国家/地区拨号代码”:{“类型”:“整数”},
    “country short”:{“type”:“string”}
    },
    “必填项”:[“国家”、“国家拨码”、“国家短路”]
    };
    $.extendext(true,'extend',jsonResult,json1,json2);
    log(JSON.stringify(jsonResult));
    /*输出->
    {“财产”:
    {“街道地址”:{“类型”:“字符串”},
    “城市”:{“类型”:“字符串”},
    “状态”:{“类型”:“字符串”},
    “国家”:{“类型”:“字符串”},
    “国家/地区拨号代码”:{“类型”:“整数”},
    “country short”:{“type”:“string”}
    },
    “必填项”:[“街道地址”、“城市”、“州”、“国家”、“国家拨码”、“国家简称”]
    }
    */
    
    这似乎
    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;
    }
    
    <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>