public 和私有類欄位[雙語]

丁香園F2E發表於2018-12-23
一些提案擴充套件了現有的 JavaScript 類, 帶來了新功能. 該文章解釋了 在 V8 v7.2 和 Chrome 72 中新的 public 類欄位語法, 和即將到來的私有類欄位語法.
Several proposals expand the existing JavaScript class syntax with new functionality. This article explains the new public class fields syntax in V8 v7.2 and Chrome 72, as well as the upcoming private class fields syntax.
這裡是一個程式碼示例, 其建立了一個名為 IncreasingCounter 的類的例項:
Here’s a code example that creates an instance of a class named IncreasingCounter:
const counter = new IncreasingCounter();
counter.value;
// logs 'Getting the current value!'
// → 0
counter.increment();
counter.value;
// logs 'Getting the current value!'
// → 1
複製程式碼
注意, 訪問 value 在返回結果之前執行了一些程式碼(i.e., 其列印了一條訊息). 現在問一下自己, 在 JavaScript 中, 你將如何實施該類? ?
Note that accessing the value executes some code (i.e., it logs a message) before returning the result. Now ask yourself, how would you implement this class in JavaScript? ?

ES2015 類語法

ES2015 class syntax
這裡是使用 ES2015 類語法實現 IncreasingCounter 的方法:
Here’s how IncreasingCounter could be implemented using ES2015 class syntax:
class IncreasingCounter {
  constructor() {
    this._count = 0;
  }
  get value() {
    console.log('Getting the current value!');
    return this._count;
  }
  increment() {
    this._count++;
  }
}
複製程式碼
這個類在原型上面實現了 value 取值方法, 和 increment 方法. 更有趣的是, 該類有一個構造器, 其給例項建立一個 _count 屬性, 並且設定其預設值為 0. 我們現在使用下劃線字首來標明 _count 不應該被類的例項直接使用, 但這只是一個約定; 並沒有語言強制指定的特殊語義, 所以其不是一個真正的 "私有" 屬性.
The class installs the value getter and an increment method on the prototype. More interestingly, the class has a constructor that creates an instance property _count and sets its default value to 0. We currently tend to use the underscore prefix to denote that _count should not be used directly by consumers of the class, but that’s just a convention; it’s not really a "private" property with special semantics enforced by the language.
const counter = new IncreasingCounter();
counter.value;
// logs 'Getting the current value!'
// → 0

// Nothing stops people from reading or messing with the
// `_count` instance property. ?
counter._count;
// → 0
counter._count = 42;
counter.value;
// logs 'Getting the current value!'
// → 42
複製程式碼

public 類欄位

新的 public 類欄位語法允許我們簡化類定義
The new public class fields syntax allows us to simplify the class definition:
class IncreasingCounter {
  _count = 0;
  get value() {
    console.log('Getting the current value!');
    return this._count;
  }
  increment() {
    this._count++;
  }
}
複製程式碼
_count 屬性現在很好的宣告在類的頂部. 只是宣告一些欄位的時候我們不再需要建構函式. 整齊!
The _count property is now nicely declared at the top of the class. We no longer need a constructor just to define some fields. Neat!
但是, _count 欄位依舊還是一個 public 屬性. 在這個特殊的例子下, 我們希望阻止人直接的訪問該屬性.
However, the _count field is still a public property. In this particular example, we want to prevent people from accessing the property directly.

私有類欄位

Private class fields
這就是私有類欄位的用武之地. 新的私有類欄位和 public 欄位相似, 除非 你使用 # 標記該欄位為私有. 你可以將 # 視為欄位名的一部分.
That’s where private class fields come in. The new private fields syntax is similar to public fields, except you mark the field as being private by using #. You can think of the # as being part of the field name:
class IncreasingCounter {
  #count = 0;
  get value() {
    console.log('Getting the current value!');
    return this.#count;
  }
  increment() {
    this.#count++;
  }
}
複製程式碼
私有欄位在類之外是不可訪問的:
Private fields are not accessible outside of the class body:
const counter = new IncreasingCounter();
counter.#count;
// → SyntaxError
counter.#count = 42;
// → SyntaxError
複製程式碼

public 並且靜態的屬性

Public and static properties
類欄位語法也可以用來建立 public 和 私有的 靜態屬性和方法:
Class fields syntax can be used to create public and private static properties and methods as well:
class FakeMath {
  // `PI` is a static public property.
  static PI = 22 / 7; // Close enough.

  // `#totallyRandomNumber` is a static private property.
  static #totallyRandomNumber = 4;

  // `#computeRandomNumber` is a static private method.
  static #computeRandomNumber() {
    return FakeMath.#totallyRandomNumber;
  }

  // `random` is a static public method (ES2015 syntax)
  // that consumes `#computeRandomNumber`.
  static random() {
    console.log('I heard you like random numbers…')
    return FakeMath.#computeRandomNumber();
  }
}

FakeMath.PI;
// → 3.142857142857143
FakeMath.random();
// logs 'I heard you like random numbers…'
// → 4
FakeMath.#totallyRandomNumber;
// → SyntaxError
FakeMath.#computeRandomNumber();
// → SyntaxError
複製程式碼

更簡單的子類

Simpler subclassing
當處理引入額外的欄位的子類的時候, 類欄位語法帶來的好處是更加清晰. 想象一下下面的基類 Animal:
The benefits of the class fields syntax become even clearer when dealing with subclasses that introduce additional fields. Imagine the following base class Animal:
class Animal {
  constructor(name) {
    this.name = name;
  }
}
複製程式碼
為了建立一個引入了一個額外的例項屬性的 Cat 子類, 以前, 在建立這個屬性之前你必須先呼叫 super() 來呼叫 Animal 的建構函式:
To create a Cat subclass that introduces an additional instance property, you’d previously have to call super() to run the constructor of the Animal base class before creating the property:
class Cat extends Animal {
  constructor(name) {
    super(name);
    this.likesBaths = false;
  }
  meow() {
    console.log('Meow!');
  }
}
複製程式碼
這裡有很多的模板程式碼只是為了指明 cats 不喜歡洗澡. Luckily, 類欄位語法移除了整個建構函式, 包括笨拙的 super() 呼叫:
That’s a lot of boilerplate just to indicate that cats don’t enjoy taking baths. Luckily, the class fields syntax removes the need for the whole constructor, including the awkward super() call:
class Cat extends Animal {
  likesBaths = false;
  meow() {
    console.log('Meow!');
  }
}
複製程式碼

結尾

Conclusion
public 類欄位將在 V8 v7.2 和 Chrome 72 登陸. 我們計劃在不久之後登陸 私有欄位語法.
Public class fields are shipping in V8 v7.2 and Chrome 72. We plan on shipping private class fields soon.
關於該新特性有疑問? 過於該文想作評論? 儘管在 Twitter 上面通過 @mathia ping 我!
Questions about this new feature? Comments about this article? Feel free to ping me on Twitter via @mathias!

譯者注:

  • Q: 為什麼沒有翻譯 public 這個單詞?
  • A: 用了很多翻譯工具嘗試翻譯 public class fields, 結果都是 公共類欄位, 包括 bing 翻譯, google translate. 但是我總感覺這個翻譯不夠嚴謹, public 這裡應該是指例項可以訪問的欄位, 應該是公開欄位. 並不是一些例項公共的欄位. 所以譯者保留了這個單詞, 不希望有些人在閱讀的時候會有誤解. 如果有什麼意見, 歡迎評論.
  • Q: 為什麼 Luckily 這個單詞也沒有翻譯
  • A: 為了熟悉這個單詞, 懸浮在該英文單詞之上即可看到中文, 該單詞的中文意思為: 幸運的是

譯者在翻譯的時候保留了英語原文, 希望給你一個原滋原味的閱讀體驗並且能熟悉一些常見的英文.

希望有讀者可以指出我的翻譯錯誤, 感激不盡.

譯文轉載請註明出處, 文中所有資源 LISENCE 均跟隨源資源.

其他雙語譯文:

相關文章