Skip to content

Commit a19b51a

Browse files
authored
Merge pull request #451 from ish-kafel/master
Private and protected properties and methods
2 parents 1178a85 + 86eb69a commit a19b51a

File tree

1 file changed

+95
-109
lines changed
  • 1-js/09-classes/04-private-protected-properties-methods

1 file changed

+95
-109
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,71 @@
11

2-
# Private and protected properties and methods
2+
# 私有的和受保护的属性和方法
33

4-
One of the most important principles of object oriented programming -- delimiting internal interface from the external one.
4+
面向对象编程最重要的原则之一 —— 划分出外部接口和内部接口。
55

6-
That is "a must" practice in developing anything more complex than a "hello world" app.
6+
在开发比 “hello world” 应用更复杂的东西时,这是“必须”的做法。
77

8-
To understand this, let's break away from development and turn our eyes into the real world.
8+
为了理解这一点,让我们脱离开发过程,把目光转向现实世界。
99

10-
Usually, devices that we're using are quite complex. But delimiting the internal interface from the external one allows to use them without problems.
10+
通常,我们使用的设备非常复杂。但是划分出外部接口和内部接口可以让我们使用它们而没有任何问题。
1111

12-
## A real-life example
12+
## 一个真实的例子
1313

14-
For instance, a coffee machine. Simple from outside: a button, a display, a few holes...And, surely, the result -- great coffee! :)
14+
例如咖啡机。从外面看很简单:一个按钮,一个显示器,几个洞……当然,结果就是 —— 很棒的咖啡!:)
1515

1616
![](coffee.jpg)
1717

18-
But inside... (a picture from the repair manual)
18+
但在里面……(维修手册中的图片)
1919

2020
![](coffee-inside.jpg)
2121

22-
A lot of details. But we can use it without knowing anything.
22+
有很多细节。但我们可以在不了解的情况下使用它。
2323

24-
Coffee machines are quite reliable, aren't they? We can use one for years, and only if something goes wrong -- bring it for repairs.
24+
咖啡机非常可靠,不是吗?我们可以使用好几年,只有在出现问题时 —— 进行维修。
2525

26-
The secret of reliability and simplicity of a coffee machine -- all details are well-tuned and *hidden* inside.
26+
咖啡机的可靠性和简洁性的秘诀 —— 所有细节都经过精心调整并 **隐藏** 在内部。
2727

28-
If we remove the protective cover from the coffee machine, then using it will be much more complex (where to press?), and dangerous (it can electrocute).
28+
如果我们从咖啡机上取下保护盖,那么使用它将会复杂得多(要按哪里?),并且危险(会触电)。
2929

30-
As we'll see, in programming objects are like coffee machines.
30+
正如我们所看到的,在编程中,对象就像咖啡机。
3131

32-
But in order to hide inner details, we'll use not a protective cover, but rather special syntax of the language and conventions.
32+
但是为了隐藏内部细节,我们不会使用保护盖,而是使用语言和惯例中的特殊语法。
3333

34-
## Internal and external interface
34+
## 内部接口和外部接口
3535

36-
In object-oriented programming, properties and methods are split into two groups:
36+
在面向对象的编程中,属性和方法分为两组:
3737

38-
- *Internal interface* -- methods and properties, accessible from other methods of the class, but not from the outside.
39-
- *External interface* -- methods and properties, accessible also from outside the class.
38+
- **内部接口** —— 可以通过类的其他方法访问,但不能从外部访问的方法和属性。
39+
- **外部接口** —— 也可从类的外部访问的方法和属性。
4040

41-
If we continue the analogy with the coffee machine -- what's hidden inside: a boiler tube, heating element, and so on -- is its internal interface.
41+
如果我们继续用咖啡机进行类比 —— 内部隐藏的内容:锅炉管,加热元件等 —— 是其内部的接口。
4242

43-
An internal interface is used for the object to work, its details use each other. For instance, a boiler tube is attached to the heating element.
43+
内部接口用于对象,它的细节相互使用。例如,锅炉管连接到加热元件。
4444

45-
But from the outside a coffee machine is closed by the protective cover, so that no one can reach those. Details are hidden and inaccessible. We can use its features via the external interface.
45+
但是从外面看,咖啡机内部被保护罩遮住,所以没有人可以接触到。细节被隐藏起来并且无法访问。我们可以通过外部接口使用它的功能。
4646

47-
So, all we need to use an object is to know its external interface. We may be completely unaware how it works inside, and that's great.
47+
所以,我们需要使用一个对象时只需知道它的外部接口。我们可能完全不知道它的内部是如何工作的,这很棒。
4848

49-
That was a general introduction.
49+
这是个概括的介绍。
5050

51-
In JavaScript, there are three types of properties and members:
51+
JavaScript 中,有两种类型的对象字段(属性和方法):
5252

53-
- Public: accessible from anywhere. They comprise the external interface. Till now we were only using public properties and methods.
54-
- Private: accessible only from inside the class. These are for the internal interface.
53+
- 公共的:可从任何地方访问。它们包含外部接口。直到现在我们只使用公共属性和方法。
54+
- 私有的:只能从类的内部访问。这些用于内部接口。
5555

56-
In many other languages there also exist "protected" fields: accessible only from inside the class and those extending it. They are also useful for the internal interface. They are in a sense more widespread than private ones, because we usually want inheriting classes to gain access to properly do the extension.
56+
在许多其他语言中,还存在“受保护”的字段:只能从类的内部访问和扩展它们(类似私有的,但是加上了向继承的类的访问)。它们对内部接口也很有用。它们在某种意义上比私有的属性和方法更广泛,因为我们通常希望继承类来获得正确执行扩展的访问权限。
5757

58-
Protected fields are not implemented in JavaScript on the language level, but in practice they are very convenient, so they are emulated.
58+
受保护的字段不是在 Javascript 语言级别上实现的,但实际上它们非常方便,因为它们是在 Javascript 中模拟的类定义语法。
5959

60-
In the next step we'll make a coffee machine in JavaScript with all these types of properties. A coffee machine has a lot of details, we won't model them to stay simple (though we could).
60+
现在,我们将使用所有这些类型的属性在 Javascript 中制作咖啡机。咖啡机有很多细节,我们不会对它们进行全面模拟以保持简洁(尽管我们可以)。
6161

62-
## Protecting "waterAmount"
62+
## 受保护的“waterAmount
6363

64-
Let's make a simple coffee machine class first:
64+
让我们先做一个简单的咖啡机类:
6565

6666
```js run
6767
class CoffeeMachine {
68-
waterAmount = 0; // the amount of water inside
68+
waterAmount = 0; // 内部的水量
6969

7070
constructor(power) {
7171
this.power = power;
@@ -74,22 +74,22 @@ class CoffeeMachine {
7474

7575
}
7676

77-
// create the coffee machine
77+
// 创建咖啡机
7878
let coffeeMachine = new CoffeeMachine(100);
7979

80-
// add water
80+
// 加入水
8181
coffeeMachine.waterAmount = 200;
8282
```
8383

84-
Right now the properties `waterAmount` and `power` are public. We can easily get/set them from the outside to any value.
84+
现在,属性 `waterAmount` `power` 是公共的。我们可以轻松地从外部读取/设置它们为任何值。
8585

86-
Let's change `waterAmount` property to protected to have more control over it. For instance, we don't want anyone to set it below zero.
86+
让我们将 `waterAmount` 属性更改为受保护的属性以对其进行更多控制。例如,我们不希望任何人将其值设置为小于零的数。
8787

88-
**Protected properties are usually prefixed with an underscore `_`.**
88+
**受保护的属性通常以下划线 `_` 作为前缀。**
8989

90-
That is not enforced on the language level, but there's a convention that such properties and methods should not be accessed from the outside. Most programmers follow it.
90+
这不是在语言层面强制实施的,但是有一个在程序员之间人尽皆知的惯例是不应该从外部访问这些属性和方法。
9191

92-
So our property will be called `_waterAmount`:
92+
所以我们的属性将被称为 `_waterAmount`
9393

9494
```js run
9595
class CoffeeMachine {
@@ -110,22 +110,22 @@ class CoffeeMachine {
110110

111111
}
112112

113-
// create the coffee machine
113+
// 创建咖啡机
114114
let coffeeMachine = new CoffeeMachine(100);
115115

116-
// add water
116+
// 加入水
117117
coffeeMachine.waterAmount = -10; // Error: Negative water
118118
```
119119

120-
Now the access is under control, so setting the water below zero fails.
120+
现在访问受到控制,因此将水量设置为小于零的数将会失败。
121121

122-
## Read-only "power"
122+
## 只读的“power
123123

124-
For `power` property, let's make it read-only. It sometimes happens that a property must be set at creation time only, and then never modified.
124+
对于 `power` 属性,让我们将它设为只读的。有时候一个属性必须仅在创建时设置,然后不再修改。
125125

126-
That's exactly the case for a coffee machine: power never changes.
126+
这就是咖啡机的实际情况:功率永远不会改变。
127127

128-
To do so, we only need to make getter, but not the setter:
128+
要做到这一点,我们只需要设置 getter,而不是 setter
129129

130130
```js run
131131
class CoffeeMachine {
@@ -141,18 +141,18 @@ class CoffeeMachine {
141141

142142
}
143143

144-
// create the coffee machine
144+
// 创建咖啡机
145145
let coffeeMachine = new CoffeeMachine(100);
146146

147-
alert(`Power is: ${coffeeMachine.power}W`); // Power is: 100W
147+
alert(`Power is: ${coffeeMachine.power}W`); // 功率是:100W
148148

149149
coffeeMachine.power = 25; // Error (no setter)
150150
```
151151

152-
````smart header="Getter/setter functions"
153-
Here we used getter/setter syntax.
152+
````smart header="Getter/setter 函数"
153+
这里我们使用 getter/setter 语法。
154154
155-
But most of the time `get.../set...` functions are preferred, like this:
155+
但大多数时候首选 `get.../set...` 函数,像这样:
156156
157157
```js
158158
class CoffeeMachine {
@@ -171,28 +171,28 @@ class CoffeeMachine {
171171
new CoffeeMachine().setWaterAmount(100);
172172
```
173173
174-
That looks a bit longer, but functions are more flexible. They can accept multiple arguments (even if we don't need them right now). So, for the future, just in case we need to refactor something, functions are a safer choice.
174+
这看起来有点长,但函数更灵活。他们可以接受多个参数(即使我们现在不需要它们)。
175175
176-
Surely, there's a tradeoff. On the other hand, get/set syntax is shorter, so ultimately there's no strict rule, it's up to you to decide.
176+
另一方面,get/set 语法更短,所以最终没有严格的规则,而是由你自己来决定。
177177
````
178178

179-
```smart header="Protected fields are inherited"
180-
If we inherit `class MegaMachine extends CoffeeMachine`, then nothing prevents us from accessing `this._waterAmount` or `this._power` from the methods of the new class.
179+
```smart header="受保护的字段是继承的"
180+
如果我们继承 `class MegaMachine extends CoffeeMachine`,那么无法阻止我们从新的类中的方法访问 `this._waterAmount` `this._power`
181181
182-
So protected fields are naturally inheritable. Unlike private ones that we'll see below.
182+
所以受保护的字段是自然可继承的。不像我们接下来将看到的私有字段。
183183
```
184184

185-
## Private "#waterLimit"
185+
## 私有的“#waterLimit
186186

187187
[recent browser=none]
188188

189-
There's a finished JavaScript proposal, almost in the standard, that provides language-level support for private properties and methods.
189+
在标准中几乎有个已完成的 Javascript 提案,它为私有属性和方法提供语言级支持。
190190

191-
Privates should start with `#`. They are only accessible from inside the class.
191+
私有属性和方法应该以 `#` 开头。他们只能从类的内部访问。
192192

193-
For instance, here we add a private `#waterLimit` property and extract the water-checking logic into a separate method:
193+
例如,这有一个私有属性 `#waterLimit`,以及检查水量的私有方法 `#checkWater`
194194

195-
```js
195+
```js run
196196
class CoffeeMachine {
197197
*!*
198198
#waterLimit = 200;
@@ -205,36 +205,22 @@ class CoffeeMachine {
205205
}
206206
*/!*
207207

208-
_waterAmount = 0;
209-
210-
set waterAmount(value) {
211-
*!*
212-
this.#checkWater(value);
213-
*/!*
214-
this._waterAmount = value;
215-
}
216-
217-
get waterAmount() {
218-
return this._waterAmount;
219-
}
220-
221208
}
222209

223210
let coffeeMachine = new CoffeeMachine();
224211

225212
*!*
213+
// 不能从类的外部访问其私有方法
226214
coffeeMachine.#checkWater(); // Error
227215
coffeeMachine.#waterLimit = 1000; // Error
228216
*/!*
229-
230-
coffeeMachine.waterAmount = 100; // Works
231217
```
232218

233-
On the language level, `#` is a special sign that the field is private. We can't access it from outside or from inheriting classes.
219+
在语言层面,`#` 是该字段为私有的特殊标志。我们无法从外部或从继承的类中访问它。
234220

235-
Private fields do not conflict with public ones. We can have both private `#waterAmount` and public `waterAmount` fields at the same time.
221+
私有字段不与公共字段发生冲突。我们可以同时拥有私有属性 `#waterAmount` 和公共属性 `waterAmount`
236222

237-
For instance, let's make `waterAmount` an accessor for `#waterAmount`:
223+
例如,让 `waterAmount` 成为 `#waterAmount` 的访问器:
238224

239225
```js run
240226
class CoffeeMachine {
@@ -257,74 +243,74 @@ machine.waterAmount = 100;
257243
alert(machine.#waterAmount); // Error
258244
```
259245

260-
Unlike protected ones, private fields are enforced by the language itself. That's a good thing.
246+
与受保护的字段不同,私有字段由语言本身强制执行。这是好事。
261247

262-
But if we inherit from `CoffeeMachine`, then we'll have no direct access to `#waterAmount`. We'll need to rely on `waterAmount` getter/setter:
248+
但是如果我们继承 `CoffeeMachine`,那么我们将无法直接访问 `#waterAmount`。我们需要依赖 `waterAmount` getter / setter
263249

264250
```js
265251
class MegaCoffeeMachine extends CoffeeMachine() {
266252
method() {
267253
*!*
268-
alert( this.#waterAmount ); // Error: can only access from CoffeeMachine
254+
alert( this.#waterAmount ); // 错误:只能从 CoffeeMachine 中访问
269255
*/!*
270256
}
271257
}
272258
```
273259

274-
In many scenarios such limitation is too severe. If we extend a `CoffeeMachine`, we may have legitimate reason to access its internals. That's why protected fields are used most of the time, even though they are not supported by the language syntax.
260+
在许多情况下,这种限制太严重了。如果我们扩展一个 `CoffeeMachine`,我们可能有正当理由访问其内部。这就是为什么大多数时候都会使用受保护字段的原因,即使它们不受语言语法的支持。
275261

276-
````warn
277-
Private fields are special.
262+
````warn header="私有字段不能通过 this[name] 访问"
263+
私有字段很特别。
278264
279-
Remember, usually we can access fields by this[name]:
265+
如我们所知,通常我们可以使用 `this[name]` 访问字段:
280266
281267
```js
282268
class User {
283269
...
284270
sayHi() {
285271
let fieldName = "name";
286-
alert(`Hello, ${this[fieldName]}`);
272+
alert(`Hello, ${*!*this[fieldName]*/!*}`);
287273
}
288274
}
289275
```
290276
291-
With private fields that's impossible: `this['#name']` doesn't work. That's a syntax limitation to ensure privacy.
277+
私有字段是不可能的: `this['#name']` 不起作用。这是确保私有性的语法限制。
292278
````
293279

294-
## Summary
280+
## 总结
295281

296-
In terms of OOP, delimiting of the internal interface from the external one is called [encapsulation]("https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)").
282+
就面向对象编程(OOP)而言,内部接口与外部接口的划分称为[封装]("https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)")
297283

298-
It gives the following benefits:
284+
它具有以下优点:
299285

300-
Protection for users, so that they don't shoot themselves in the feet
301-
: Imagine, there's a team of developers using a coffee machine. It was made by the "Best CoffeeMachine" company, and works fine, but a protective cover was removed. So the internal interface is exposed.
286+
保护用户,使他们不会误伤自己
287+
: 想象一下,有一群开发人员使用咖啡机。它是由“Best CoffeeMachine”公司制造的,工作正常,但保护盖被拿走了。因此内部接口暴露了出来。
302288

303-
All developers are civilized -- they use the coffee machine as intended. But one of them, John, decided that he's the smartest one, and made some tweaks in the coffee machine internals. So the coffee machine failed two days later.
289+
所有的开发人员都是文明的 —— 他们按照预期使用咖啡机。但其中一个人,约翰,被认为是最聪明的,并且决定让他在咖啡机内部做一些调整。然而咖啡机两天后就坏了。
304290

305-
That's surely not John's fault, but rather the person who removed the protective cover and let John do his manipulations.
291+
这肯定不是约翰的错,而是那个取下保护套并让约翰执行自己操作的人的错。
306292

307-
The same in programming. If a user of a class will change things not intended to be changed from the outside -- the consequences are unpredictable.
293+
编程也一样。如果一个类的使用者想要改变那些本不打算从外部改变的东西 —— 后果是不可预测的。
308294

309-
Supportable
310-
: The situation in programming is more complex than with a real-life coffee machine, because we don't just buy it once. The code constantly undergoes development and improvement.
295+
可支持的
296+
: 编程的情况比现实生活中的咖啡机更复杂,因为我们不只是购买一次。代码不断经历着发展和改进。
311297

312-
**If we strictly delimit the internal interface, then the developer of the class can freely change its internal properties and methods, even without informing the users..**
298+
**如果我们严格界定内部接口,那么类的开发人员可以自由地更改其内部属性和方法,即使没有通知用户。**
313299

314-
It's much easier to develop, if you know that certain methods can be renamed, their parameters can be changed, and even removed, because no external code depends on them.
300+
如果你是这样的类的开发者,当知道由于没有外部代码的依赖,私有方法可以安全地重命名,它们的参数可以改变,甚至可以删除是很棒的事。
315301

316-
For users, when a new version comes out, it may be a total overhaul, but still simple to upgrade if the external interface is the same.
302+
对于使用者来说,当新版本出现时,它可能是全面的内部检查,但如果外部接口相同,则仍然很容易升级。
317303

318-
Hiding complexity
319-
: People adore to use things that are simple. At least from outside. What's inside is a different thing.
304+
隐藏复杂性
305+
: 人们喜欢使用简单的东西。至少从外部来看是这样。内部的东西则是另外一回事了。
320306

321-
Programmers are not an exception.
307+
程序员也不例外。
322308

323-
**It's always convenient when implementation details are hidden, and a simple, well-documented external interface is available.**
309+
**隐藏实施细节时总是很方便,并且提供了一个简单的,记录详细的外部接口。**
324310

325-
To hide internal interface we use either protected or public properties:
311+
为了隐藏内部接口,我们使用受保护的或私有的属性:
326312

327-
- Protected fields start with `_`. That's a well-known convention, not enforced at the language level. Programmers should only access a field starting with `_` from its class and classes inheriting from it.
328-
- Private fields start with `#`. JavaScript makes sure we only can access those from inside the class.
313+
- 受保护的字段以 `_` 开头。这是一个众所周知的惯例,没有在语言层面强制执行。程序员只应该通过它的类和它继承的类中访问以 `_` 开头的字段。
314+
- 私有字段以 `#` 开头。JavaScript 确保我们只能访问类中的内容。
329315

330-
Right now, private fields are not well-supported among browsers, but can be polyfilled.
316+
目前,在各浏览器中不支持私有字段,但可以用 polyfill 解决。

0 commit comments

Comments
 (0)