譯者按: 爲何偏要用**#**符號?javascript
本文采用意譯,版權歸原做者全部html
proposal-class-fields與proposal-private-methods定義了 Class 的私有屬性以及私有方法,這 2 個提案已經處於 Stage 3,這就意味着它們已經基本肯定下來了,等待被加入到新的 ECMAScript 版本中。事實上,最新的 Chrome 已經支持了 Class 私有屬性。java
那麼,對於 Class 的私有屬性與私有方法,它們到底是什麼呢?它們是怎樣工做的?爲何要使用**#**符號來定義呢?git
Class 的私有屬性語法以下:github
class Point { #x; #y; constructor(x, y) { this.#x = x; this.#y = y; } equals(point) { return this.#x === point.#x && this.#y === point.#y; } }
咱們能夠將其語法理解爲 2 個部分:小程序
私有屬性與公共屬性的定義方式幾乎是同樣的,只是須要在屬性名稱前面添加**#**符號:微信小程序
class Foo { publicFieldName = 1; #privateFieldName = 2; }
定義私有屬性的時候也能夠不用賦值:微信
class Foo { #privateFieldName; }
引用私有屬性也只須要使用**#**就行了。函數
class Foo { publicFieldName = 1; #privateFieldName = 2; add() { return this.publicFieldName + this.#privateFieldName; } }
其中,**this.#**能夠簡化,去掉 this 也沒問題,下面兩種寫法是等價的:性能
method() { #privateFieldName; }
method() { this.#privateFieldName; }
對於私有屬性,咱們是不能夠直接經過 Class 實例來引用的,這也是私有屬性的原本含義。可是有一種狀況除外,在 Class 定義中,咱們能夠引用 Class 實例的私有屬性:
class Foo { #privateValue = 42; static getPrivateValue(foo) { return foo.#privateValue; } } Foo.getPrivateValue(new Foo()); // >> 42
其中,foo是Foo的實例,在 Class 定義中,咱們能夠經過 foo 來引用私有屬性**#privateValue**。
Class 的私有屬性是提案proposal-class-fields的一部分,這個提案只關注 Class 的屬性,它並無對 Class 的方法進行任何修改。而 Class 的私有方法是提案proposal-class-fields的一部分。
Class 的私有方法語法以下:
class Foo { constructor() { this.#method(); } #method() { // ... } }
咱們也能夠將函數賦值給私有屬性:
class Foo { constructor() { this.#method(); } #method = () => { // ... }; }
咱們不能直接經過 Class 實例引用私有屬性,咱們只能在 Class 定義中引用它們:
class Foo { #bar; method() { this.#bar; // Works } } let foo = new Foo(); foo.#bar; // Invalid!
另外,要作到真正的私有的話,咱們應該沒法檢測這個私有屬性是否存在,所以,咱們須要容許定義同名的公共屬性:
class Foo { bar = 1; // public bar #bar = 2; // private bar }
若是咱們不容許公共屬性與私有屬性同名,咱們則能夠經過給同名的公共屬性複製監測該私有屬性是否存在:
foo.bar = 1; // Error: `bar` is private! (報錯,說明私有屬性存在)
不報錯也行:
foo.bar = 1; foo.bar; // `undefined` (賦值失敗,說明私有屬性存在)
對於 subclass 應該一樣如此,它也容許公共屬性與私有屬性同名:
class Foo { #fieldName = 1; } class Bar extends Foo { fieldName = 2; // Works! }
關於 Class 私有屬性的封裝,能夠參考Why is encapsulation a goal of this proposal?。
不少人都有一個疑問,爲何 JS 不能學習其餘語言,使用private來定義私有屬性和私有方法?爲何要使用奇怪的**#**符號?
使用 private 的話,代碼要舒服不少:
class Foo { private value; equals(foo) { return this.value === foo.value; } }
不少語言使用 private 來定義私用屬性,以下:
class EnterpriseFoo { public bar; private baz; method() { this.bar; this.baz; } }
對於這些語言屬性,私用屬性和公共屬性的引用方式是相同的,所以他們可使用 private 來定義私有屬性。
可是,對於 JavaScript 來講,咱們不能使用 this.field 來引用私有屬性(我接下來會解釋緣由),咱們須要在語法層面上區分私有屬性和公共屬性。在定義和引用私有屬性的時候,使用**#**符號,私有屬性與公共屬性能夠很好地區分開來。
引用私有屬性的時候,咱們須要this.#field,而不是this.field,緣由以下:
class Dict extends null { #data = something_secret; add(key, value) { this[key] = value; } get(key) { return this[key]; } } new Dict().get("#data"); // 返回私有屬性
所以,私有屬性與公共屬性的引用方式必須不同,不然會破壞**this['field']**語法。
這篇文章遵循Creative Commons Attribution 4.0 International License。
Fundebug專一於JavaScript、微信小程序、微信小遊戲、支付寶小程序、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了10億+錯誤事件,付費客戶有Google、360、金山軟件、百姓網等衆多品牌企業。歡迎你們免費試用!
轉載時請註明做者Fundebug以及本文地址: [https://blog.fundebug.com/2019/04/23/javascript-class-private-field-and-private-method/