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

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


当前回答

这是一个经典的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

其他回答

我使用这个可比函数来生成JSON可比的对象副本:

Var可比= o => (typeof o != '对象' || !o)?o: 种(o) .sort()。减少((c键)= > (c[主要]=可比(o(例子)),c), {}); / /演示: var = {1, c: 4 b:[2、3],d: {e:“5”,f:零}}; var b = {b:[2、3],c: 4 d: {f: null, e:“5”},答:1}; console.log (JSON.stringify(可比(a))); console.log (JSON.stringify(可比(b))); console.log(JSON.stringify(comparable(a)) == JSON.stringify(comparable(b))); < div id = " div " > < / div >

在测试中很方便(大多数测试框架都有一个is函数)。如。

is(JSON.stringify(comparable(x)), JSON.stringify(comparable(y)), 'x must match y');

如果捕捉到差异,则记录字符串,使差异可见:

x must match y
got      {"a":1,"b":{"0":2,"1":3},"c":7,"d":{"e":"5","f":null}},
expected {"a":1,"b":{"0":2,"1":3},"c":4,"d":{"e":"5","f":null}}.

排序对象(字典) 比较JSON字符串 函数areTwoDictsEqual(dictA, dictB) { 函数sortDict(dict) { var keys = Object.keys(dict); keys.sort (); var newDict = {}; For (var i=0;我< keys.length;我+ +){ Var key = keys[i]; Var值= dict[key]; newDict[key] = value; } 返回newDict; } 返回JSON.stringify(sortDict(dictA)) == JSON.stringify(sortDict(dictB)); }

这是一个经典的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

下面是一个使用ES6+的解决方案

// this comparison would not work for function and symbol comparisons
// this would only work best for compared objects that do not belong to same address in memory
// Returns true if there is no difference, and false otherwise


export const isObjSame = (obj1, obj2) => {
    if (typeof obj1 !== "object" && obj1 !== obj2) {
        return false;
    }

    if (typeof obj1 !== "object" && typeof obj2 !== "object" && obj1 === obj2) {
        return true;
    }

    if (typeof obj1 === "object" && typeof obj2 === "object") {
        if (Array.isArray(obj1) && Array.isArray(obj2)) {
            if (obj1.length === obj2.length) {
                if (obj1.length === 0) {
                    return true;
                }
                const firstElemType = typeof obj1[0];

                if (typeof firstElemType !== "object") {
                    const confirmSameType = currentType =>
                        typeof currentType === firstElemType;

                    const checkObjOne = obj1.every(confirmSameType);
                    const checkObjTwo = obj2.every(confirmSameType);

                    if (checkObjOne && checkObjTwo) {
                        // they are primitves, we can therefore sort before and compare by index
                        // use number sort
                        // use alphabet sort
                        // use regular sort
                        if (firstElemType === "string") {
                            obj1.sort((a, b) => a.localeCompare(b));
                            obj2.sort((a, b) => a.localeCompare(b));
                        }
                        obj1.sort((a, b) => a - b);
                        obj2.sort((a, b) => a - b);

                        let equal = true;

                        obj1.map((element, index) => {
                            if (!isObjSame(element, obj2[index])) {
                                equal = false;
                            }
                        });

                        return equal;
                    }

                    if (
                        (checkObjOne && !checkObjTwo) ||
                        (!checkObjOne && checkObjTwo)
                    ) {
                        return false;
                    }

                    if (!checkObjOne && !checkObjTwo) {
                        for (let i = 0; i <= obj1.length; i++) {
                            const compareIt = isObjSame(obj1[i], obj2[i]);
                            if (!compareIt) {
                                return false;
                            }
                        }

                        return true;
                    }

                    // if()
                }
                const newValue = isObjSame(obj1, obj2);
                return newValue;
            } else {
                return false;
            }
        }

        if (!Array.isArray(obj1) && !Array.isArray(obj2)) {
            let equal = true;
            if (obj1 && obj2) {
                const allKeys1 = Array.from(Object.keys(obj1));
                const allKeys2 = Array.from(Object.keys(obj2));

                if (allKeys1.length === allKeys2.length) {
                    allKeys1.sort((a, b) => a - b);
                    allKeys2.sort((a, b) => a - b);

                    allKeys1.map((key, index) => {
                        if (
                            key.toLowerCase() !== allKeys2[index].toLowerCase()
                        ) {
                            equal = false;
                            return;
                        }

                        const confirmEquality = isObjSame(obj1[key], obj2[key]);

                        if (!confirmEquality) {
                            equal = confirmEquality;
                            return;
                        }
                    });
                }
            }

            return equal;

            // return false;
        }
    }
};

为了比较简单的键/值对对象实例的键,我使用:

function compareKeys(r1, r2) {
    var nloops = 0, score = 0;
    for(k1 in r1) {
        for(k2 in r2) {
            nloops++;
            if(k1 == k2)
                score++; 
        }
    }
    return nloops == (score * score);
};

一旦比较了键,一个简单的for. in循环就足够了。

复杂度是O(N*N), N是键的个数。

我希望/猜测我定义的对象不会拥有超过1000个属性…