JavaScript中的对象比较\[重复\]

JavaScript

米亚神无

2020-03-09

在JavaScript中比较对象的最佳方法是什么?

例:

var user1 = {name : "nerd", org: "dev"};
var user2 = {name : "nerd", org: "dev"};
var eq = user1 == user2;
alert(eq); // gives false

我知道如果两个对象引用的是完全相同的对象则它们相等,但是有没有办法检查它们是否具有相同的属性值?

以下方法对我有用,但这是唯一的可能性吗?

var eq = Object.toJSON(user1) == Object.toJSON(user2);
alert(eq); // gives true

第386篇《JavaScript中的对象比较\[重复\]》来自Winter(https://github.com/aiyld/aiyld.github.io)的站点

4个回答
JinJin 2020.03.10

如果要显式检查方法,则可以使用method.toSource()或method.toString()方法。

老丝小胖蛋蛋 2020.03.10

我写了这段代码用于对象比较,它似乎可以工作。检查断言:


function countProps(obj) {
    var count = 0;
    for (k in obj) {
        if (obj.hasOwnProperty(k)) {
            count++;
        }
    }
    return count;
};

function objectEquals(v1, v2) {

    if (typeof(v1) !== typeof(v2)) {
        return false;
    }

    if (typeof(v1) === "function") {
        return v1.toString() === v2.toString();
    }

    if (v1 instanceof Object && v2 instanceof Object) {
        if (countProps(v1) !== countProps(v2)) {
            return false;
        }
        var r = true;
        for (k in v1) {
            r = objectEquals(v1[k], v2[k]);
            if (!r) {
                return false;
            }
        }
        return true;
    } else {
        return v1 === v2;
    }
}

assert.isTrue(objectEquals(null,null));
assert.isFalse(objectEquals(null,undefined));

assert.isTrue(objectEquals("hi","hi"));
assert.isTrue(objectEquals(5,5));
assert.isFalse(objectEquals(5,10));

assert.isTrue(objectEquals([],[]));
assert.isTrue(objectEquals([1,2],[1,2]));
assert.isFalse(objectEquals([1,2],[2,1]));
assert.isFalse(objectEquals([1,2],[1,2,3]));

assert.isTrue(objectEquals({},{}));
assert.isTrue(objectEquals({a:1,b:2},{a:1,b:2}));
assert.isTrue(objectEquals({a:1,b:2},{b:2,a:1}));
assert.isFalse(objectEquals({a:1,b:2},{a:1,b:3}));

assert.isTrue(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}));
assert.isFalse(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:27}}));

assert.isTrue(objectEquals(function(x){return x;},function(x){return x;}));
assert.isFalse(objectEquals(function(x){return x;},function(y){return y+2;}));
达蒙小胖 2020.03.10

以下算法将处理自引用数据结构,数字,字符串,日期,当然还有简单嵌套的javascript对象:

在以下情况下,对象被视为等效

  • 它们完全相等===(首先解开String和Number以确保42等于Number(42)
  • 或者它们都是日期并且具有相同的日期 valueOf()
  • 或者它们都是相同的类型,而不是null和...
    • 它们不是对象,并且每个对象相等==(捕获数字/字符串/布尔值)
    • 或者,忽略具有undefined值的属性,它们具有相同的属性,所有这些属性都被递归等效。

功能文本不认为功能相同。该测试不足,因为函数可能具有不同的闭包。只有这样===说,函数才被认为是相等的(但是如果您选择这样做,则可以轻松扩展该等效关系)。

避免了可能由循环数据结构引起的无限循环areEquivalent试图证明相等性并递归到对象的属性中时,它会跟踪需要进行子比较的对象。如果可以证明相等性,则对象之间的某些可到达属性路径会有所不同,然后必须存在最短的此类可到达路径,并且最短可到达路径不能包含两个路径中都存在的循环。即,递归比较对象时可以假定相等。假设存储在属性中areEquivalent_Eq_91_2_34,使用后将其删除,但是如果对象图已经包含此类属性,则行为未定义。必须使用这种marker属性,因为javascript不支持使用任意对象作为键的字典。

function unwrapStringOrNumber(obj) {
    return (obj instanceof Number || obj instanceof String 
            ? obj.valueOf() 
            : obj);
}
function areEquivalent(a, b) {
    a = unwrapStringOrNumber(a);
    b = unwrapStringOrNumber(b);
    if (a === b) return true; //e.g. a and b both null
    if (a === null || b === null || typeof (a) !== typeof (b)) return false;
    if (a instanceof Date) 
        return b instanceof Date && a.valueOf() === b.valueOf();
    if (typeof (a) !== "object") 
        return a == b; //for boolean, number, string, xml

    var newA = (a.areEquivalent_Eq_91_2_34 === undefined),
        newB = (b.areEquivalent_Eq_91_2_34 === undefined);
    try {
        if (newA) a.areEquivalent_Eq_91_2_34 = [];
        else if (a.areEquivalent_Eq_91_2_34.some(
            function (other) { return other === b; })) return true;
        if (newB) b.areEquivalent_Eq_91_2_34 = [];
        else if (b.areEquivalent_Eq_91_2_34.some(
            function (other) { return other === a; })) return true;
        a.areEquivalent_Eq_91_2_34.push(b);
        b.areEquivalent_Eq_91_2_34.push(a);

        var tmp = {};
        for (var prop in a) 
            if(prop != "areEquivalent_Eq_91_2_34") 
                tmp[prop] = null;
        for (var prop in b) 
            if (prop != "areEquivalent_Eq_91_2_34") 
                tmp[prop] = null;

        for (var prop in tmp) 
            if (!areEquivalent(a[prop], b[prop]))
                return false;
        return true;
    } finally {
        if (newA) delete a.areEquivalent_Eq_91_2_34;
        if (newB) delete b.areEquivalent_Eq_91_2_34;
    }
}
Near神无Pro 2020.03.10
  Utils.compareObjects = function(o1, o2){
    for(var p in o1){
        if(o1.hasOwnProperty(p)){
            if(o1[p] !== o2[p]){
                return false;
            }
        }
    }
    for(var p in o2){
        if(o2.hasOwnProperty(p)){
            if(o1[p] !== o2[p]){
                return false;
            }
        }
    }
    return true;
};

比较仅一个级别的对象的简单方法。

问题类别

JavaScript Ckeditor Python Webpack TypeScript Vue.js React.js ExpressJS KoaJS CSS Node.js HTML Django 单元测试 PHP Asp.net jQuery Bootstrap IOS Android