TypeScript:对象相等比较(对象等于对象) [英] TypeScript : Object Equality Comparison (Object Equals Object)

查看:410
本文介绍了TypeScript:对象相等比较(对象等于对象)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have found this (personally) convenient answer that fits my needs: https://stackoverflow.com/a/6713782/2678218

但是,由于我使用的是 TypeScript ,因此可以通过 Generics 使用类似的东西:

But since I am using TypeScript, I can have something like this with 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 语句.但是我不确定该拿走什么,也不确定是否会有更好的代码.因此,我将问题留在这里,让大家投票给最佳答案.

I'm sure that since we're using <T> here, we can refactor the code. One thing's for sure is by removing some if statements that are not needed anymore. But i am not confident of which to take away and also not sure if there will be a more optimal code for this. So I'll leave the question here and have everyone vote for the best answer.

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

In this context, what I actually mean by equality of two objects is when two objects of the same type have equal values of every property.

推荐答案

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

@Lostfields mentions that someone could pass any for the type T, but that's not a big concern, since using any is telling the compiler not to type check anything. If this leads to undesirable behavior at runtime, I'd place the responsibility for dealing with this on the code that passed in any, instead of the code inside equals(). One use of the type system is indeed to eliminate some unnecessary runtime checks, with the caveat that you still need to do sanitize any data being passed in from untrusted sources. Are you building a library that will be used by developers who might not even be using TypeScript? Then do not relax any runtime checks. Are you building code to be used internally or by other TypeScript developers who depend on your typings? Then by all means eliminate unnecessary checks.

话虽这么说,但我不能删除该实现中的许多检查.即使在知道TypeScript已确定 x y true false >属于同一类型.(在接下来的内容中,我将把 equals()视为独立的函数而不是方法.添加 this 或您认为合适的任何对象名称)

That being said, I don't you can remove many of the checks in that implementation. Each of the conditionals checked might be true or false at runtime, even knowing that TypeScript has decided that x and y are of the same type. (In what follows I will be treating equals() as a standalone function instead of a method. Add this or whatever the object name is as you see fit)

让我们检查一下每个人:

Let's examine each one:

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

  • (x === y): True for equals(x,x), false for equals(x, Object.assign({},x)). This one has to stay.

((!(x instanceof Object | |!(y instanceof Object))):您可能决定用替换的那个(!(x instanceof Object)),因为实际上TypeScript中的类型是 Object 还是不是,所以 x instanceof Object 应该是与 y instanceof Object 相同.不过,有人可能会执行 equals(0,new Number(0))并通过TypeScript中的类型检查.在乎防止这种情况发生.

((!(x instanceof Object) || !(y instanceof Object)): This one you might decide to replace with just (!(x instanceof Object)), since in practice a type in TypeScript is either an Object or it is not, and so x instanceof Object should be the same as y instanceof Object. Still, someone might do equals(0, new Number(0)) which passes the type check in TypeScript. It's up to you if you care about guarding against that.

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

(x.constructor !== y.constructor): False for two structurally identical classes, such as class A{}; class B{}; equals(new A(), new B()). If you're not worried about structurally identical but distinct classes, you can eliminate this check.

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

(!x.hasOwnProperty(p)): This check has nothing to do with TypeScript; it has to stay.

对于下一种情况,请考虑

For the next case, consider

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中允许使用额外的属性.

    • (!y.hasOwnProperty(p)) and (y.hasOwnProperty(p) && !x.hasOwnProperty(p)): These could be true or false for instances of Foo, or any type with optional properties. Or any subtype of a type without optional properties, since extra properties are allowed in TypeScript.

      (x [p] === y [p])(typeof(x [p])!=='object')(!equals(x [p],y [p])):由于与上述相同的原因,它们可以为true或false,这可以通过传入具有单个属性的类型看到上面提到的类型.也就是说,如果 equals(x,y)需要运行时检查,那么 equals({foo:x},{foo:y})将需要相同的运行时检查

      (x[p] === y[p]), (typeof (x[p]) !== 'object'), (!equals(x[p], y[p])): These can be true or false for the same reasons as above, which can be seen by passing in a type with a single property of the types mentioned above. That is, if equals(x,y) needs a runtime check, then equals({foo: x},{foo: y}) will need the same runtime check.

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

      So, it's up to you. Feel free to leave the implementation alone. Extra runtime checks don't hurt anything, after all. Feel free to remove some checks if you don't think you'll need them; again, you're the only one who knows how crazy the users of equals() will be. For example, what would you do about this:

      interface Ouroboros {
          prop: Ouroboros;
      }
      let x = {} as Ouroboros;
      x.prop = x;
      
      let y = {} as Ouroboros;
      y.prop = y;
      
      console.log(equals(x,y))
      

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

      Do you care about circular references? If not, don't worry. If so, then you need to harden your equality check to deal with it.

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

      Hope that helps; good luck!

      这篇关于TypeScript:对象相等比较(对象等于对象)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆