繁体   English   中英

TypeScript:对象相等性比较(对象等于对象)

[英]TypeScript : Object Equality Comparison (Object Equals Object)

我已经找到了适合我需求的(个人)便捷答案: https : //stackoverflow.com/a/6713782/2678218

但是由于我使用的是TypeScript ,所以我可以在Generics中使用类似的东西:

private equals<T>(x: T, y: T) {
    if (x === y) {
        return true; // if both x and y are null or undefined and exactly the same
    } else if (!(x instanceof Object) || !(y instanceof Object)) {
        return false; // if they are not strictly equal, they both need to be Objects
    } else if (x.constructor !== y.constructor) {
        // they must have the exact same prototype chain, the closest we can do is
        // test their constructor.
        return false;
    } else {
        for (const p in x) {
            if (!x.hasOwnProperty(p)) {
                continue; // other properties were tested using x.constructor === y.constructor
            }
            if (!y.hasOwnProperty(p)) {
                return false; // allows to compare x[ p ] and y[ p ] when set to undefined
            }
            if (x[p] === y[p]) {
                continue; // if they have the same strict value or identity then they are equal
            }
            if (typeof (x[p]) !== 'object') {
                return false; // Numbers, Strings, Functions, Booleans must be strictly equal
            }
            if (!this.equals(x[p], y[p])) {
                return false;
            }
        }
        for (const p in y) {
            if (y.hasOwnProperty(p) && !x.hasOwnProperty(p)) {
                return false;
            }
        }
        return true;
    }
}

我敢肯定,因为我们在这里使用<T> ,所以我们可以重构代码。 可以肯定的是,删除一些不再需要的if语句。 但是我不知道该拿走什么,也不确定是否会有更好的代码。 因此,我将问题留在这里,让大家投票给最佳答案。

在这种情况下,两个对象相等实际上是指相同类型的两个对象在每个属性上具有相等的值。

@Lostfields提到有人可以为T类型传递any值,但这不是什么大问题,因为使用any会告诉编译器不要对任何内容进行类型检查。 如果这在运行时导致不良行为,我将负责处理此问题的代码传递给any ,而不是equals()内部的代码。 类型系统的一种用途确实是消除了一些不必要的运行时检查,但需要注意的是,您仍然需要清理从不可信来源传入的所有数据。 您是否正在建立一个供甚至可能不使用TypeScript的开发人员使用的库? 然后不要放松任何运行时检查。 您是在构建供内部使用还是由其他TypeScript开发人员使用(取决于您的键入)的代码? 然后一定要消除不必要的检查。


话虽这么说,但我不能删除该实现中的许多检查。 即使知道TypeScript已确定xy属于同一类型,所检查的每个条件在运行时也可能为truefalse (在接下来的内容中,我将equals()作为独立函数而不是方法来对待。添加this名称或您认为合适的任何对象名称)

让我们检查每个:

  • (x === y) :对于equals(x,x)为true,对于equals(x, Object.assign({},x))为false。 这一个必须留下。

  • ((!(x instanceof Object) || !(y instanceof Object)) :您可能会决定只用(!(x instanceof Object))来替换它,因为实际上TypeScript中的类型要么是Object要么是否,因此x instanceof Object应该与y instanceof Object相同。尽管如此,有人可能会做equals(0, new Number(0))并通过TypeScript中的类型检查。如果您关心防止这种情况,则取决于您。

  • (x.constructor !== y.constructor) :对于两个结构相同的类(例如class A{}; class B{}; equals(new A(), new B())(x.constructor !== y.constructor)为False class A{}; class B{}; equals(new A(), new B()) class A{}; class B{}; equals(new A(), new B()) class A{}; class B{}; equals(new A(), new B()) 如果您不担心结构相同但又不同的类,则可以取消此检查。

  • (!x.hasOwnProperty(p)) :此检查与TypeScript无关; 它必须留下。

对于下一种情况,请考虑

interface Foo { foo?: string, bar: number, baz?: boolean };
const x: Foo = { foo: 'hello', bar: 12 };
const y: Foo = { bar: 12, baz: false };
equals(x, y);
  • (!y.hasOwnProperty(p))(y.hasOwnProperty(p) && !x.hasOwnProperty(p)) :对于Foo实例或具有可选属性的任何类型,它们可以为true或false。 或没有可选属性的类型的任何子类型,因为TypeScript允许额外的属性。

  • (x[p] === y[p])(typeof (x[p]) !== 'object')(!equals(x[p], y[p])) :这些可以成立或false(与上述相同),可以通过传入具有上述类型的单个属性的类型来看出。 也就是说,如果equals(x,y)需要运行时检查,那么equals({foo: x},{foo: y})将需要相同的运行时检查。


因此,取决于您。 随意离开实施。 毕竟,额外的运行时检查不会对您造成任何伤害 如果您认为不需要,可以随时删除一些支票; 同样,您是唯一知道equals()用户将变得多么疯狂的人。 例如,您将如何处理:

interface Ouroboros {
    prop: Ouroboros;
}
let x = {} as Ouroboros;
x.prop = x;

let y = {} as Ouroboros;
y.prop = y;

console.log(equals(x,y))

您是否关心循环引用? 如果没有,请不要担心。 如果是这样,那么您需要加强相等性检查以对其进行处理。


希望能有所帮助; 祝好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM