public 和私有类字段[双语]

2,331 阅读6分钟
一些提案扩展了现有的 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 均跟随源资源.

其他双语译文: