【问题标题】:How to compare JavaScript objects obtained by parsing JSON?如何比较解析 JSON 得到的 JavaScript 对象?
【发布时间】:2017-05-16 18:08:29
【问题描述】:
wtf1 = JSON.parse('{"asdf": "jkl"}');
wtf2 = JSON.parse('{"asdf": "jkl"}');

wtf1 == wtf2; // false
wtf1 === wtf2; // false

我最近偶然发现了上述问题。例如,这种违反直觉的情况使得在 JSON 层次结构深处的数组中查找特定对象变得很困难。

有什么方法可以比较这些对象吗?

【问题讨论】:

  • 解析前为什么不比较一下?
  • 不,这些对象是不同的。您需要逐个比较它们...
  • 仅供参考,===== 在比较对象时是等效的,因为您是在比较引用,而不是对象本身。
  • 比较两个对象的键的简单解决方案非常简单且防弹。

标签: javascript arrays json javascript-objects


【解决方案1】:

对于简单的对象,您可以再次将它们字符串化(使用有序键)并比较字符串。例如:

var wtf1 = JSON.parse('{"a": "a", "b": "b"}');
var wtf2 = JSON.parse('{"b": "b", "a": "a"}');
var s1 =  JSON.stringify(wtf1, Object.keys(wtf1).sort());
var s2 =  JSON.stringify(wtf2, Object.keys(wtf2).sort());
console.log('wtf1 is equal to wtf2: ', (s1 == s2));

对于带有原型等的嵌套对象,您可能应该使用_.isEqual 或任何其他提供深度相等测试的库。

请注意,一般来说,正确实现对象的深度相等测试并非易事,它不像迭代和比较键/值那么简单。但是,由于“对象是通过解析 JSON 获得的”,因此您可以跳过大部分复杂情况并递归地对嵌套值进行字符串化。

【讨论】:

  • 不可靠。比如'{"a": 1, "b": 2}''{"b": 2, "a": 1}'呢?
  • @dfsq 已解决
  • @Pavel - 您的排序不涉及嵌套值。
  • 这甚至不应该被回答。这个问题已经在 SO 上被问过很多次了
  • 另外,这是非常奇怪的将数组作为第二个参数传递给JSON.stringify。不仅是错误的,而且看起来将它作为第二个参数传递很重要。
【解决方案2】:

我认为在解析为对象之前先比较它们会更好。但这只有在它们完全相同的情况下才有效,包括属性的顺序

var obj1 = {name: "potato", age: 10}
var obj2 = {name: "potato", age: 10}

console.log(obj1 == obj2) //false

console.log(JSON.stringify(obj1) == JSON.stringify(obj2)) //true

var obj1 = {name: "potato", age: 10}
var obj2 = {age: 10, name: "potato"}

console.log(obj1 == obj2) //false

console.log(JSON.stringify(obj1) == JSON.stringify(obj2)) //also false

【讨论】:

  • 它们在一个数组中,而一个数组是另一个对象的属性……总的来说,它们在 JSON 层次结构中非常深入。我想我可以只 JSON.parse 整个 JSON,然后处理它。这个事实使你的方法有点困难
  • 但是你没有解析它们,对吧?只是比较它们。但同样:它们需要在属性上具有相同的结构/顺序。也许您可以在比较之前对属性进行排序
  • 如果我解析了整个 JSON,那么特别是我解析了这两个对象。
【解决方案3】:

您无法比较对象(因为它们是不同的),但您可以遍历每个属性并比较它们(并再次递归检查它们是否是对象):

function compare(obj1,obj2){
   //check for obj2 overlapping props
   if(!Object.keys(obj2).every(key=>obj1.hasOwnProperty(key))){
      return false;
   }

   //check every key for being same
   return Object.keys(obj1).every(function(key){

      //if object
      if((typeof obj1[key]=="object" )&&( typeof obj2[key]=="object")){

          //recursively check
          return compare(obj1[key],obj2[key]);
      }else{

          //do the normal compare
          return obj1[key]===obj2[key];
      }
   });
}

http://jsbin.com/zagecigawi/edit?js

【讨论】:

  • 如果 obj1 的所有键都在 obj2 中,而 obj2 的所有键都不在 obj1 中怎么办?
  • @TravisJ 那么它将失败
  • 那行得通。虽然,也许您应该确保没有密钥重复。 key=>{if(!keys.has(key))keys.add(key)} 我认为应该可以工作
  • "keys.every 不是函数"
  • @mhodges 已编辑...(我可以简单地将 Set 绑定到它吗?)
【解决方案4】:

这将比较响应和模型的 JSON 结构(它将只比较键而不比较值,并且适用于任何层次结构)

function compareObjects(response, model) {

    if (response == "" && model == "") {
        return false;
    }

    if (typeof (response) != "object" && typeof (model) != "object") {
        var response = JSON.parse(response);
        var model = JSON.parse(model);
    }

    if (typeof (response) != typeof (model)) {
        return false;
    } else {
        switch (Object.prototype.toString.call(model)) {
            case '[object]':
                var x;
                var mKeys = Object.keys(model);
                for (x in mKeys) {
                    return compareObjects(Object.keys(model)[x], Object.keys(response)[x]);
                }
                break;

            case '[object Array]':
                return compareObjects(model[0], response[0]);

            case "[object String]":
                return model == response;

            default:
                return true;
        }
    }
}
var response = '[{"educationId":5,"degreeName":"Bacheltecture - B.Arch"},{"educationId":2,"degreeName":"Bachelor of Arts - B.A. "},{"educationId":3,"degreeName":"Bachelor of Ayurvedic Medicine  Surgery - B.A.M.S. "}]';
var model = '[{"degreeName":null},{"educationId":null,"degreeName":null},{"educationId":null,"degreeName":null}]';

var output = compareObjects(response, model);

console.log(output);

【讨论】:

    【解决方案5】:

    JS 中的两个对象即使具有相同的属性也永远不会相等。您可以对对象进行字符串化并比较这些字符串或遍历所有属性(但如果您需要深度比较则很难)

    【讨论】:

      【解决方案6】:

      您也可以使用 loadash。 使用 _.isEqual("object1", "object2");

      var obj1 = {"prop1" : 2, "prop2" : 3 };
      var obj2 = {"prop1" : 2, "prop2" : 3};
      
      console.dir(_.isEqual(obj1, obj2)) 
      <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

      第二种方法是 JSON.stringify(obj1) === JSON.stringify(obj2)

      【讨论】:

        【解决方案7】:

        我建议使用库实现进行对象相等检查。试试lodash version

        var object = { 'a': 1 };
        var other = { 'a': 1 };
        
        _.isEqual(object, other);
        // => true
        

        【讨论】:

          猜你喜欢
          • 2011-12-27
          • 1970-01-01
          • 2020-01-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多