如何比较通过解析的JSON得到的JavaScript对象?

5
wtf1 = JSON.parse('{"asdf": "jkl"}');
wtf2 = JSON.parse('{"asdf": "jkl"}');

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

最近我遇到了上述问题。这种违反直觉的情况使得在JSON层级结构中查找特定对象变得困难。

有没有什么方法可以比较这样的对象?


1
为什么不在解析之前进行比较呢? - Artur Trapp
2
不行,这些对象是不一样的。你需要逐个键进行比较... - Jonas Wilms
2
只是提醒一下,当比较对象时,=====是等效的,因为你在比较引用,而不是对象本身。 - mhodges
1
比较两个对象的键的微不足道的解决方案非常简单和牢靠。 - dfsq
7个回答

7

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

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获得的”,因此您可以跳过大部分复杂性,并递归地将嵌套值字符串化。


4
不可靠。例如,'{"a": 1, "b": 2}''{"b": 2, "a": 1}'怎么办? - dfsq
@dfsq提到 - Pavel P
2
@Pavel - 你的排序没有考虑到嵌套值。 - Travis J
这个问题不应该被回答。这个问题已经在SO上被问了很多次了。 - mhodges
而且,将数组作为 JSON.stringify 的第二个参数传递是非常奇怪的。这不仅是错误的,而且会让人误以为将其作为第二个参数传递很重要。 - dfsq
@dfsq 为什么感觉奇怪?这是一个你想要转换成字符串的键数组。对于简单情况来说,我认为这已经足够了。 - Pavel P

3

我认为最好在解析成对象之前先比较它们。但这仅适用于它们完全相同,包括属性的顺序。

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进行JSON.parse,然后进行操作。这个事实使得您的方法有点困难。 - user4385532
但是你有它们未解析的,对吧?只需比较它们。但是需要注意:它们的属性需要具有相同的结构/顺序。也许在比较之前可以对属性进行排序。 - Artur Trapp
如果我已经解析了整个JSON,那么特别地,我已经解析了这两个对象。 - user4385532

2

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

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


"keys.every 不是一个函数" - mhodges
@mhodges编辑...(我是不是可以将Set简单地绑定到它上面?) - Jonas Wilms
@Jonasw,我搞砸了,请尝试使用这个链接:https://repl.it/IB2z/5。实际上不需要创建一个集合,因为对象属性已经是唯一的了。您可以比较键数组的长度并使用`hasOwnProperty`。 - mhodges
@mhodges 是的,我决定这样做了。使用集合可能会更快(我相信),但是我不能那么简单地迭代它... - Jonas Wilms
@Jonasw - 啊,是的,它们是唯一的。请忽略之前的重复评论。 - Travis J
显示剩余4条评论

1

你可以使用 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)。

1
这将比较响应和模型的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);

0

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


0

我建议使用库实现对象相等性检查。尝试使用lodash版本

var object = { 'a': 1 };
var other = { 'a': 1 };

_.isEqual(object, other);
// => true

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接