2017-10-15 128 views
1

我注意到有兩種不同的方法可以有效地在JavaScript中編寫一個類(或類的東西)。使用簡單的計數器類爲例:Class vs函數返回對象

一個真正的類(用作new Counter1()

class Counter1 { 
    constructor(count = 0) { 
    this.count = count; 
    } 
    inc() { 
    this.count++; 
    } 
    get() { 
    return this.count; 
    } 
} 

的函數返回一個對象(用作Counter2()

function Counter2(count = 0) { 
    return { 
    inc() { 
     count++; 
    }, 
    get() { 
     return count; 
    }, 
    }; 
} 

我有很多的代碼可以用這兩種風格中的任何一種書寫。我應該使用哪個?

這是我的理解:

Counter1可以instanceof和繼承使用,但是更詳細的,沒有真正的私有屬性(如count屬性暴露)。

Counter2更簡潔,具有真正的私有方法/狀態(只是函數中的局部變量),但不能與instanceof和繼承一起使用。它還會爲每個實例創建incget函數的新副本,這可能會影響性能?我不知道。

+0

與功能構造新的關鍵字可能雖然原型的屬性仍然無法訪問私有作用域變量,但最好。 – user7951676

回答

-2

我把它放在一個jsperf頁面在這裏測試新的實例創建的速度,無論是風格:https://jsperf.com/class-vs-object-2

這裏是我的計算機上的結果(每秒創建新實例):

Test     Chrome   Firefox   Edge 
new Counter1(); 217,901,688  2,086,800,399  31,106,382 
Counter2();   30,495,508  36,113,817  9,232,171 

我不知道爲什麼Firefox編號與class是如此之高(希望它沒有注意到代碼沒有效果,並且忽略了整個事情),或者爲什麼Edge數字如此之低。

因此,至少在性能方面,真實的類要快得多,可能是因爲它避免了爲每個實例創建方法的新副本的開銷。

雖然類的冗長和缺乏私人狀態令人討厭,但我認爲性能優勢更重要,但它取決於具體情況。

編輯

我所做的結果對象的測試呼叫inc()get()以及和數量基本一致:

Test     Chrome   Firefox   Edge 
new Counter1(); 215,352,342 2,072,278,834 23,570,036 
Counter2();  14,309,836  35,564,201 9,801,748 
+0

我接受這個答案是因爲它是最強烈的論點,兩種都可能的情況。 – Jesse

0

我建議使用classes,正因爲如此,

  • 類方法是non-enumerable

    類定義集枚舉標誌爲假在「原型」所有類成員的方法。這很好,因爲如果我們通過一個對象for..in,我們通常不希望它是類方法。

  • 類有一個默認constructor() {}

    如果在class構造沒有constructor,然後一個空函數生成,一樣的,如果我們寫了constructor() {}

  • 類總是use strict

    類構造內的所有代碼會自動在strict mode

  • 類也可能包括getters/setters。
  • Static Methods

    我們也可以分配方法的類的功能,而不是它的「原型」。

您可以進一步here

+4

(1)一個普通的舊對象文字可以包括getter和setter。 (2)在第二個例子中,「類方法」或「靜態方法」可以直接放在'Counter2'上。 (3)這裏不清楚爲什麼有一個默認的構造函數。 (4)請提供關於「總是嚴格使用類」的說明文檔,我認爲這是ES6模塊,總是使用「嚴格」。 – 2017-10-15 02:48:48

0

兩者都不應該對性能有很大影響。雖然類(示例中的Counter1)在技術上略有更好的性能,但如果您每秒創建數千個類的實例(這可能是一個糟糕的設計選擇),這只是顯而易見的。

至於其他優點,兩者都有優點和缺點。 FunFunFunction是學習JavaScript的優秀YouTube頻道,也是我第一次瞭解工廠功能的地方(Counter)。渠道擁有者強烈支持這些使用class es。

其中一個原因是你不能在this關鍵字中使用類實現在JS中的方式獲得一致的行爲,因爲它可能涉及類似於調用函數的HTML元素而不是你期待的目標。

有關更多詳細信息,請參閱this video

當然,這只是論證的一個方面,我相信也有使用class的論點。我更喜歡工廠的功能,但最終你只需要選擇一個,然後滾動。

+0

您對「this」這個關鍵字的處理很棘手,特別是在混合方法和回調,雖然一些靜態類型系統(TypeScript,Flow)可以幫助確保你做到了正確(儘管如此,他們經常會錯誤的) – Jesse

0

應該使用哪一個?

這個問題基本上是個人喜好的問題。真正的面向對象的信徒當然會採用class的方法。一個明顯的區別是,這將允許您繼承Counter1,但不清楚爲什麼你會這樣做,甚至OOP愛好者都警告不要構建過於複雜的類層次結構。

是的,第二個選擇確實將問題的方法放在每個實例上,而不是原型上。是的,這確實會造成一些理論上的性能損失。但是這不是你需要擔心的事情,除非你正在爲一百萬個對象中的每一個寫一個計數器。

假設您正在使用某種類型的編譯器或在原生ES6環境中運行。如果由於某種原因,你不是,那麼當然你的第二個選擇的優點是它可以在任何瀏覽器中運行最近十年(如果你將方法改寫爲inc: function() { count++; })。