【问题标题】:How to compare two JSON have the same properties without order?如何比较两个没有顺序的具有相同属性的JSON?
【发布时间】:2014-11-20 20:37:33
【问题描述】:

我尝试比较这两个 JSON 对象:

<input type="hidden" id="remoteJSON" name="remoteJSON" value='{"allowExternalMembers": "false", "whoCanJoin": "CAN_REQUEST_TO_JOIN"}' /><br />
<input type="hidden" id="localJSON" name="localJSON" value='{"whoCanJoin": "CAN_REQUEST_TO_JOIN", "allowExternalMembers": "false"}' /><br />

我用 javascript 获得了值,并尝试与 JSON.stringify(remoteJSON) == JSON.stringify(localJSON) 进行比较,但这返回 false:似乎属性的顺序很重要。

我什至尝试与this solution 进行深度比较,但总是得到错误的回报。

有没有一种快速的方法来解决 jQuery 的问题(即用于比较 JSON 的库)?

【问题讨论】:

  • 你能告诉我们你是如何尝试深度比较的吗?
  • "总是得到一个错误的返回" --- 不,它不会 jsfiddle.net/pyLqhujo 如果该函数返回 false 它字面意思是你的对象是不同的。
  • @zerkms: 我以前比较的是字符串而不是对象,所以现在可以返回 true 语句...+1
  • 抱歉,这是我的错

标签: javascript jquery json


【解决方案1】:

Lodash _.isEqual 允许你这样做:

var
remoteJSON = {"allowExternalMembers": "false", "whoCanJoin": "CAN_REQUEST_TO_JOIN"},
    localJSON = {"whoCanJoin": "CAN_REQUEST_TO_JOIN", "allowExternalMembers": "false"};
    
console.log( _.isEqual(remoteJSON, localJSON) );
&lt;script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"&gt;&lt;/script&gt;

【讨论】:

    【解决方案2】:

    Lodash isEqual() 方法是比较两个 JSON 对象的最佳方法。

    这将不考虑对象中键的顺序并检查对象的相等性。示例

    const object1 = {
      name: 'ABC',
      address: 'India'
    };
        
    const object2 = {
      address: 'India',
      name: 'ABC'
    };
        
    JSON.stringify(object1) === JSON.stringify(object2)
    // false
        
    _.isEqual(object1, object2)
    // true
    

    参考 - https://lodash.com/docs/#isEqual

    如果序列不会改变,JSON.stringify() 将比 Lodash 的 isEqual() 方法快。

    参考 - https://www.measurethat.net/Benchmarks/Show/1854/0/lodash-isequal-test

    【讨论】:

      【解决方案3】:

      在 javascript 中比较两个 json 字符串的简单方法

      var obj1 = {"name":"Sam","class":"MCA"};
      var obj2 = {"class":"MCA","name":"Sam"};
      
      var flag=true;
      
      if(Object.keys(obj1).length==Object.keys(obj2).length){
          for(key in obj1) { 
              if(obj1[key] == obj2[key]) {
                  continue;
              }
              else {
                  flag=false;
                  break;
              }
          }
      }
      else {
          flag=false;
      }
      console.log("is object equal"+flag);
      

      【讨论】:

      • 这适用于原始值。如果 obj[key] 和 obj2[key 有嵌套对象,那么这将失败,因为对象是通过它们的引用进行比较的。
      【解决方案4】:

      DeepCompare 方法比较两个 json 对象..

      deepCompare = (arg1, arg2) => {
        if (Object.prototype.toString.call(arg1) === Object.prototype.toString.call(arg2)){
          if (Object.prototype.toString.call(arg1) === '[object Object]' || Object.prototype.toString.call(arg1) === '[object Array]' ){
            if (Object.keys(arg1).length !== Object.keys(arg2).length ){
              return false;
            }
            return (Object.keys(arg1).every(function(key){
              return deepCompare(arg1[key],arg2[key]);
            }));
          }
          return (arg1===arg2);
        }
        return false;
      }
      
      console.log(deepCompare({a:1},{a:'1'})) // false
      console.log(deepCompare({a:1},{a:1}))   // true

      【讨论】:

        【解决方案5】:

        此代码将独立于参数对象顺序验证 json。

        var isEqualsJson = (obj1,obj2)=>{
            keys1 = Object.keys(obj1);
            keys2 = Object.keys(obj2);
        
            //return true when the two json has same length and all the properties has same value key by key
            return keys1.length === keys2.length && Object.keys(obj1).every(key=>obj1[key]==obj2[key]);
        }
        
        var obj1 = {a:1,b:2,c:3};
        var obj2 = {a:1,b:2,c:3}; 
        
        console.log("json is equals: "+ isEqualsJson(obj1,obj2));
        alert("json is equals: "+ isEqualsJson(obj1,obj2));

        【讨论】:

          【解决方案6】:

          我改编并修改了this tutorial 的代码,以编写一个对两个 JS 对象进行深度比较的函数。

          const isEqual = function(obj1, obj2) {
              const obj1Keys = Object.keys(obj1);
              const obj2Keys = Object.keys(obj2);
          
              if(obj1Keys.length !== obj2Keys.length) {
                  return false;
              }
          
              for (let objKey of obj1Keys) {
                  if (obj1[objKey] !== obj2[objKey]) {
                      if(typeof obj1[objKey] == "object" && typeof obj2[objKey] == "object") {
                          if(!isEqual(obj1[objKey], obj2[objKey])) {
                              return false;
                          }
                      } 
                      else {
                          return false;
                      }
                  }
              }
          
              return true;
          };
          

          该函数比较两个对象的相同键的各自值。此外,如果这两个值是对象,它也会使用递归对它们执行深度比较。

          希望这会有所帮助。

          【讨论】:

            【解决方案7】:

            lodash 可以工作,即使是 angular 5 也可以测试,http://jsfiddle.net/L5qrfx3x/

            var remoteJSON = {"allowExternalMembers": "false", "whoCanJoin": 
               "CAN_REQUEST_TO_JOIN"};
            var localJSON = {"whoCanJoin": "CAN_REQUEST_TO_JOIN", 
              "allowExternalMembers": "false"};
            
             if(_.isEqual(remoteJSON, localJSON)){
                 //TODO
                }
            

            它可以工作,要以角度安装,请关注this

            【讨论】:

              【解决方案8】:

              这个问题提醒了如何确定两个 JavaScript 对象的相等。 所以,我会选择this通用函数

              比较 JS 对象:

              function objectEquals(x, y) {
                  // if both are function
                  if (x instanceof Function) {
                      if (y instanceof Function) {
                          return x.toString() === y.toString();
                      }
                      return false;
                  }
                  if (x === null || x === undefined || y === null || y === undefined) { return x === y; }
                  if (x === y || x.valueOf() === y.valueOf()) { return true; }
              
                  // if one of them is date, they must had equal valueOf
                  if (x instanceof Date) { return false; }
                  if (y instanceof Date) { return false; }
              
                  // if they are not function or strictly equal, they both need to be Objects
                  if (!(x instanceof Object)) { return false; }
                  if (!(y instanceof Object)) { return false; }
              
                  var p = Object.keys(x);
                  return Object.keys(y).every(function (i) { return p.indexOf(i) !== -1; }) ?
                          p.every(function (i) { return objectEquals(x[i], y[i]); }) : false;
              }
              

              【讨论】:

              • 所以,基本上你只是复制了this answer?
              • @Ja͢ck:或者他们误判了。
              • @BoltClock 即使是这样,这也不能回答问题,因为问题不在于使用的比较函数。
              • @Ja͢ck:是的。抱歉,我并没有试图为这个答案辩护——无论是抄袭还是错误归因都不会改变任何事情。不过还是等作者修复吧。 (不过,这是一个善意的尝试来回答这个问题,因此不属于 NAA。)
              • @BoltClock 不用担心,这篇文章可能已被标记,乍一看,错误归因似乎是最合乎逻辑的问题:)
              【解决方案9】:

              在 VueJs 函数中,您也可以使用它...使用递归的可行解决方案。基本学分 Samadhan Sakhale

                   check_objects(obj1, obj2) {
                          try {
                              var flag = true;
              
                              if (Object.keys(obj1).length == Object.keys(obj2).length) {
                                  for (let key in obj1) {
              
                                      if(typeof (obj1[key]) != typeof (obj2[key]))
                                      {
                                          return false;
                                      }
              
                                      if (obj1[key] == obj2[key]) {
                                          continue;
                                      }
              
                                      else if(typeof (obj1[key]) == typeof (new Object()))
                                      {
                                          if(!this.check_objects(obj1[key], obj2[key])) {
                                              return false;
                                          }
                                      }
                                      else {
                                          return false;
                                      }
                                  }
                              }
                              else {
                                  return false
                              }
                          }
                          catch {
              
                              return false;
                          }
              
                          return flag;
                      },
              

              【讨论】:

                【解决方案10】:

                我们使用node-deep-equal 项目,它实现了与nodejs 相同的深度相等比较

                google serach for deep-equal on npm 会告诉你很多选择

                【讨论】:

                  【解决方案11】:

                  如果您尝试比较这两个对象与我的目标相同:即仅反序列化一个有效对象,在这种情况下,我建议您使用以下方法:

                  using Newtonsoft.Json;
                  
                  try
                  {
                      var myObj = JsonConvert.DeserializeObject<**YourTargetObjectType**>(jsonString, new JsonSerializerSettings
                      {
                          MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
                          MissingMemberHandling = MissingMemberHandling.Error
                      });
                  }catch (MissingMemberException mme)
                  {
                      
                      throw;
                  }
                  

                  如果捕获到错误,那么您的对象不属于 YourTargetObjectType。否则很好,你可以对第二个对象做同样的事情。

                  带有 MissingMemberHandling 的 JsonSerializerSetings 可以解决问题。在 mme 异常对象中,您可以检查哪个属性属性失败。这会验证额外的属性、缺失的属性和/或拼写错误的属性。

                  因此,在您的情况下,您应该有一个 Object 用作​​比较两个对象的参考。

                  【讨论】:

                    【解决方案12】:

                    由于@zerkems 评论:

                    我应该将我的字符串转换为 JSON 对象,然后调用 equal 方法:

                    var x = eval("(" + remoteJSON + ')');
                    var y = eval("(" + localJSON + ')');
                    
                    function jsonequals(x, y) {
                        // If both x and y are null or undefined and exactly the same
                        if ( x === y ) {
                            return true;
                        }
                    
                        // If they are not strictly equal, they both need to be Objects
                        if ( ! ( x instanceof Object ) || ! ( y instanceof Object ) ) {
                            return false;
                        }
                    
                        // They must have the exact same prototype chain, the closest we can do is
                        // test the constructor.
                        if ( x.constructor !== y.constructor ) {
                            return false;
                        }
                    
                        for ( var p in x ) {
                            // Inherited properties were tested using x.constructor === y.constructor
                            if ( x.hasOwnProperty( p ) ) {
                                // Allows comparing x[ p ] and y[ p ] when set to undefined
                                if ( ! y.hasOwnProperty( p ) ) {
                                    return false;
                                }
                    
                                // If they have the same strict value or identity then they are equal
                                if ( x[ p ] === y[ p ] ) {
                                    continue;
                                }
                    
                                // Numbers, Strings, Functions, Booleans must be strictly equal
                                if ( typeof( x[ p ] ) !== "object" ) {
                                    return false;
                                }
                    
                                // Objects and Arrays must be tested recursively
                                if ( !equals( x[ p ],  y[ p ] ) ) {
                                    return false;
                                }
                            }
                        }
                    
                        for ( p in y ) {
                            // allows x[ p ] to be set to undefined
                            if ( y.hasOwnProperty( p ) && ! x.hasOwnProperty( p ) ) {
                                return false;
                            }
                        }
                        return true;
                    }
                    

                    【讨论】:

                    • 不要使用eval();有JSON.parse() 或$.parseJSON()。
                    猜你喜欢
                    • 1970-01-01
                    • 2014-11-09
                    • 1970-01-01
                    • 1970-01-01
                    • 2010-12-16
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-08-06
                    • 2020-03-23
                    相关资源
                    最近更新 更多