严格相等运算符将告诉您两个对象类型是否相等。然而,是否有一种方法来判断两个对象是否相等,就像Java中的哈希码值一样?

堆栈溢出问题JavaScript中有hashCode函数吗?类似于这个问题,但需要一个更学术的答案。上面的场景说明了为什么有必要有一个,我想知道是否有等效的解决方案。


当前回答

我的版本,包括发现差异的地方,以及差异是什么。

function DeepObjectCompare(O1, O2)
{
    try {
        DOC_Val(O1, O2, ['O1->O2', O1, O2]);
        return DOC_Val(O2, O1, ['O2->O1', O1, O2]);
    } catch(e) {
        console.log(e.Chain);
        throw(e);
    }
}
function DOC_Error(Reason, Chain, Val1, Val2)
{
    this.Reason=Reason;
    this.Chain=Chain;
    this.Val1=Val1;
    this.Val2=Val2;
}

function DOC_Val(Val1, Val2, Chain)
{
    function DoThrow(Reason, NewChain) { throw(new DOC_Error(Reason, NewChain!==undefined ? NewChain : Chain, Val1, Val2)); }

    if(typeof(Val1)!==typeof(Val2))
        return DoThrow('Type Mismatch');
    if(Val1===null || Val1===undefined)
        return Val1!==Val2 ? DoThrow('Null/undefined mismatch') : true;
    if(Val1.constructor!==Val2.constructor)
        return DoThrow('Constructor mismatch');
    switch(typeof(Val1))
    {
        case 'object':
            for(var m in Val1)
            {
                if(!Val1.hasOwnProperty(m))
                    continue;
                var CurChain=Chain.concat([m]);
                if(!Val2.hasOwnProperty(m))
                    return DoThrow('Val2 missing property', CurChain);
                DOC_Val(Val1[m], Val2[m], CurChain);
            }
            return true;
        case 'number':
            if(Number.isNaN(Val1))
                return !Number.isNaN(Val2) ? DoThrow('NaN mismatch') : true;
        case 'string':
        case 'boolean':
            return Val1!==Val2 ? DoThrow('Value mismatch') : true;
        case 'function':
            if(Val1.prototype!==Val2.prototype)
                return DoThrow('Prototype mismatch');
            if(Val1!==Val2)
                return DoThrow('Function mismatch');
            return true;
        default:
            return DoThrow('Val1 is unknown type');
    }
}

其他回答

对于那些使用Node的人来说,在本地util库中有一个叫做isDeepStrictEqual的方便方法可以实现这一点。

const util = require('util');

const obj1 = {
  foo: "bar",
  baz: [1, 2]
};

const obj2 = {
  foo: "bar",
  baz: [1, 2]
};


obj1 == obj2 // false
util.isDeepStrictEqual(obj1, obj2) // true

https://nodejs.org/api/util.html#util_util_isdeepstrictequal_val1_val2

这是一个经典的javascript问题!我创建了一个方法来检查深度对象是否相等,其特性是能够从比较中选择要忽略的属性。 参数是要比较的两个对象,加上一个可选的字符串化属性-忽略相对路径数组。

function isObjectEqual( o1, o2, ignorePropsArr=[]) {
    // Deep Clone objects
    let _obj1 = JSON.parse(JSON.stringify(o1)),
        _obj2 = JSON.parse(JSON.stringify(o2));
    // Remove props to ignore
    ignorePropsArr.map( p => { 
        eval('_obj1.'+p+' = _obj2.'+p+' = "IGNORED"');
    });
    // compare as strings
    let s1 = JSON.stringify(_obj1),
        s2 = JSON.stringify(_obj2);
    // return [s1==s2,s1,s2];
    return s1==s2;
}

// Objects 0 and 1 are exact equals
obj0 = { price: 66544.10, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj1 = { price: 66544.10, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj2 = { price: 66544.12, RSIs: [0.000432334, 0.00046531], candles: {A: 543, B: 321, C: 4322}}
obj3 = { price: 66544.13, RSIs: [0.000432334, 0.00046531], candles: {A: 541, B: 321, C: 4322}}
obj4 = { price: 66544.14, RSIs: [0.000432334, 0.00046530], candles: {A: 543, B: 321, C: 4322}}

isObjectEqual(obj0,obj1) // true
isObjectEqual(obj0,obj2) // false
isObjectEqual(obj0,obj2,['price']) // true
isObjectEqual(obj0,obj3,['price']) // false
isObjectEqual(obj0,obj3,['price','candles.A']) // true
isObjectEqual(obj0,obj4,['price','RSIs[1]'])   // true

我之前添加了一个答案,但它不是完美的,但这个将检查对象的相等性

function equalObjects(myObj1, myObj2){ let firstScore = 0; let secondScore = 0; let index=0; let proprtiesArray = []; let valuesArray = []; let firstLength = 0; let secondLength = 0; for (const key in myObj1) { if (myObj1.hasOwnProperty(key)) { firstLength += 1; proprtiesArray.push(key); valuesArray.push(myObj1[key]); firstScore +=1; } } for (const key in myObj2) { if (myObj2.hasOwnProperty(key)) { secondLength += 1; if (valuesArray[index] === myObj2[key] && proprtiesArray[index] === key) { secondScore +=1; } //console.log(myObj[key]); index += 1; } } if (secondScore == firstScore && firstLength === secondLength) { console.log("true", "equal objects"); return true; } else { console.log("false", "not equal objects"); return false; } } equalObjects({'firstName':'Ada','lastName':'Lovelace'},{'firstName':'Ada','lastName':'Lovelace'}); equalObjects({'firstName':'Ada','lastName':'Lovelace'},{'firstName':'Ada','lastName1':'Lovelace'}); equalObjects({'firstName':'Ada','lastName':'Lovelace'},{'firstName':'Ada','lastName':'Lovelace', 'missing': false});

纯JS方法:我的答案是基于生成一个返回相同值的字符串,无论属性顺序是否相同。设置对象可用于切换大小写和空白是否重要。(为了避免失去焦点,我没有包括那些支持函数,或者我猜应该在任何实用程序集中的isObject。)

这里也没有显示,但为了减少字符串比较时间,如果对象很大,你想加快比较,你也可以散列字符串和比较子字符串;这只适用于非常大的对象(当然也有很小的机会出现错误的相等)。

然后你可以比较genObjStr(obj1) ?= genObjStr(obj2)

function genObjStr(obj, settings) {
// Generate a string that corresponds to an object guarenteed to be the same str even if
// the object have different ordering. The string would largely be used for comparison purposes

var settings = settings||{};
var doStripWhiteSpace = defTrue(settings.doStripWhiteSpace);
var doSetLowerCase = settings.doSetLowerCase||false;

if(isArray(obj)) {
    var vals = [];
    for(var i = 0; i < obj.length; ++i) {
        vals.push(genObjStr(obj[i], settings));
    }
    vals = arraySort(vals);
    return vals.join(`,`);

} else if(isObject(obj)) {

    var keys = Object.keys(obj);
    keys = arraySort(keys);

    var vals = [];
    for(var key of keys) {
        
        var value = obj[key];
        
        value = genObjStr(value, settings);

        if(doStripWhiteSpace) {
            key = removeWhitespace(key);
            var value = removeWhitespace(value);
        };
        if(doSetLowerCase) {
            key = key.toLowerCase();
            value = value.toLowerCase();
        }

        vals.push(value);
    }
    var str = JSON.stringify({keys: keys, vals: vals});
    return str
} else {
    if(doStripWhiteSpace) {
        obj = removeWhitespace(obj);
    };
    if(doSetLowerCase) {
        obj = obj.toLowerCase();
    }
    return obj
}

}

var obj1 = {foo: 123, bar: `Test`};
var obj2 = {bar: `Test`, foo: 123};

console.log(genObjStr(obj1) == genObjStr(obj1))

简单来说:

const compare = (x, y) => {
  const srt = (obj) => JSON.stringify(obj)?.split('').sort().join('');
  return srt(x) === srt(y);
};

// ----- How to use ---
const a = {'one':1, 'two':2,'three':3};
const b = {'two':2, 'one':1, 'three':3}; //note same values as (const a)
const c = {'one':1, 'two':2,'three':3};
const d = {'one':1, 'two':2,'four':4};

compare(a, b); //true
compare(a, c); //true
compare(a, d); //false

//----- BUT! -----
JSON.stringify(a) === JSON.stringify(b); //false

//----- AND -----
compare({}, {}); //true
compare({}, undefined); //false
compare(undefined, undefined); //true
compare(undefined, ''); //false
compare(undefined, null); //false
compare(null, null); //true
compare('', ''); //true