爲何 JavaScript 的私有屬性使用 # 符號

這幾天 JavaScript 的私有屬性又成爲了前端社區熱議的話題。緣由很簡單,這傢伙長這樣:前端

驚不驚喜!意不意外!git

並且 TC39 委員會以及對此達成了一致意見,而且該提案已經進入了 stage 3。在 es 規範階段 stage 3 是候選提案,又很大的可能會進入到下一個標準。到目前爲止,已經能夠肯定會進入 es2019(es10) 標準的有 optional-catch-binding 和 proposal-json-superset。而這個 private 大概也只能進入到 es2020 後的標準了。github

TC39 委員會解釋道,他們也是作了深思熟慮最終選擇了 # 符號,而沒有使用 private 關鍵字。其中還討論了把 private# 符號一塊兒使用的方案。而且還打算預留了一個 @ 關鍵字做爲 protected 屬性😄,不過這個 @ 已經被 decorator 使用了。npm

咱們在此就不討論這個語法到底醜不醜了,這不顯而易見的嗎,還用討論嗎。咱們討論一下爲何要使用 # 符號。json

有人說,「若是這個進入了規範,我就不再用 JavaScript了,之後項目都用 TypeScript 寫」。函數

這就有點由不得你了,咱們看 TypeScript 的官網介紹:this

TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.spa

TypeScript 是 JavaScript 的超集,言外之意就是 js 有的 ts 也全都有。對於一個已經進入 stage 3 的提案,ts 固然不會坐視不理的。ts 也正在抓緊支持這個語法:All Bloomberg Changes for Private Fields and Methodscode

也有人疑問:「爲何 ts 的私有屬性就可使用 private 關鍵字,而 js 就不行呢?」cdn

由於 ts 的 private 和這個 # 語法徹底是不一樣的東西。TypeScript 是一種靜態類型語言而不是強類型語言(有爭議)。private 只是在編譯時作檢查,最終生成的 js 代碼中被 private 修飾的屬性依然是公開的。

那爲何不使用下劃線(_)呢,畢竟這個已是私有屬性的非正式的最佳實踐了?

之因此不選擇下劃線是出於兼容性考慮,另外一個因爲兼容性而妥協的提案是 JavaScript 社區由一個庫引起的「smoosh門」事件到底怎麼回事? 因爲下劃線是合法的 js 變量標識符因此不少的代碼都使用了下劃線,若是新的 js 規範把下劃線開頭的變量做爲私有屬性,那麼會致使不少就代碼沒法運行。好比知名的 lodash 和 underscore 庫就是使用的下劃線,這兩個庫每週在 npm 的下載量是 2 千萬。

「爲何不使用 private?」

這裏有一個經典的例子:

class Foo {
  private value;

  equals(foo) {
    return this.value === foo.value;
  }
}
複製代碼

在不少面嚮對象語言中都有這種寫法,判斷類的兩個實例是否相等。若是在 js 中也這麼寫,會有一些問題。

在靜態類型語言中,咱們能夠明確的知道傳入的參數是 Foo 類型,所以在 Fooequals 方法中咱們能夠訪問 foo 的私有屬性 value。可是 js 是動態類型的,咱們沒法知道參數 foo 的類型,若是咱們傳入了 {value: '123'} 會,則函數的行爲不符合咱們的預期。這也致使了該函數有時訪問的是私有屬性,有時訪問的是公有屬性。

另外一方面,私有屬性只在類的內部能夠訪問,外部沒法訪問,甚至不知道此變量的存在。所以在 JavaScript 中同名的私有屬性和公有屬性能夠同時存在,二者使用 # 作區分。

若是使用 private 進行修飾,則咱們能夠探測類的私有屬性:

foo.bar = 1; // Error: `bar` is private! (boom... detected)
複製代碼

或者:

foo.bar = 1;
foo.bar; // `undefined` (boom... detected again)
複製代碼

PS:雖然社區的總體意見是使用 private 代替 #,可是 TC39 的意見很堅定。

最後,這種引入私有屬性的方式,其實隱式的爲 js 引入了靜態類型。

相關文章
相關標籤/搜索