簡體   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