如何在javascript中断言部分深度相等/比较对象?

如何在javascript中断言部分深度相等/比较对象?,javascript,Javascript,我有一个API,我想断言至少返回了预期的数据。我不在乎是否返回更多数据 因此,我想比较两个对象(expected和actual),其中expected的所有属性必须等于actual,但actual可能包含更多属性: var expected = { foo: 1, bar: { x1: 42, a1: [ 1, 2, { x: 7

我有一个API,我想断言至少返回了预期的数据。我不在乎是否返回更多数据

因此,我想比较两个对象(
expected
actual
),其中
expected
的所有属性必须等于
actual
,但
actual
可能包含更多属性:

var expected = {
    foo: 1,
    bar: {
        x1: 42,
        a1: [
            1,
            2,
            {
                x: 7
            }
        ]
    }
}

var actual = {
    foo: 1,
    whatever: 55, // to be ignored
    additional: { // to be ignored
        ignore: 1
    },
    bar: {
        x1: 42,
        a1: [
            1,
            2,
            {
                x: 7,
                y: 8   // to be ignored
            }
        ]
    }
}

partiallyEqual(expected, actual) // returns true
还有一些例子:

如果
actual
包含额外的元素,则阵列可能(可选)受到部分等效的影响

partiallyEqual([1, 3], [1, 2, 3]) // return true
partiallyEqual([3, 1], [1, 2, 3]) // return false (different order)

我使用这个递归函数,这是我不久前写的:

Object.prototype.equals = function(to) {
    for (var prop in to) {
        if (this.hasOwnProperty(prop) && to.hasOwnProperty(prop)) {
            if (to[prop] && typeof this[prop] == "object" && typeof to[prop] == "object") {
                if (!this[prop].equals(to[prop])) {
                    return false
                }
            } else if (this[prop] != to[prop]) {
                return false
            }
        }
    }
    return true;
};

({ x: { a: 1, b: 2 } }).equals({ x: { a: 1, b: 2 } }) => true
({ x: { a: 1, b: 2 } }).equals({ x: { a: 1, b: 1 } }) => false
({ x: [1,2] }).equals({ x: { 1:1,2:2 } }) => true (doesn't differentiate between array and/or object)

此函数在发现旧对象与新对象之间存在差异时,将立即返回false。如果新对象具有旧对象的所有属性,则它可以包含任何内容。

对于不同的情况,深度相等可能很棘手,例如
NaN!==NaN
并且可能存在循环引用。最近我编写了一个简单的带有递归和循环引用检查的deep equal check util函数,它应该非常简单。您可以忽略一些长度检查来完成部分相等


github上的源代码:

您是否尝试过Chai的
deepEqual
?是的,但它是严格相等的,id不会忽略任何属性,因为您的用例是
deepEqual
的一个小变化,我建议看一下这里:根据您的需要调整一下。一个可能的解决方案可能是创建一个
actual
副本,在比较之前剥离
预期的
中不包含的所有属性。对于可能正确的小对象,但如果对象很大,则可能不是最佳解决方案。请查看并执行您的
Object.prototype
扩展正确。我使用名为prop的函数来实现它:function prop(to,name,func){
Object.defineProperty(to.prototype,name,{value:func,writable:true,configurable:true});return func;}
它用作休耕
prop(Object,'equals',function(to){…})
这些可以链接:
prop(Object,'equals',function(to){prop(Array,'equals',function(to){…})
,顺便说一句,扩展Object也扩展了Array,因为它扩展了一切
Object.prototype.equals = function(to) {
    for (var prop in to) {
        if (this.hasOwnProperty(prop) && to.hasOwnProperty(prop)) {
            if (to[prop] && typeof this[prop] == "object" && typeof to[prop] == "object") {
                if (!this[prop].equals(to[prop])) {
                    return false
                }
            } else if (this[prop] != to[prop]) {
                return false
            }
        }
    }
    return true;
};

({ x: { a: 1, b: 2 } }).equals({ x: { a: 1, b: 2 } }) => true
({ x: { a: 1, b: 2 } }).equals({ x: { a: 1, b: 1 } }) => false
({ x: [1,2] }).equals({ x: { 1:1,2:2 } }) => true (doesn't differentiate between array and/or object)