Skip to content

Commit bc5b456

Browse files
authored
Merge pull request #70 from dnzg666/master
1-js/08-prototypes/01-prototype-inheritance/article.md
2 parents cee65e5 + 88d8028 commit bc5b456

1 file changed

Lines changed: 58 additions & 58 deletions

File tree

  • 1-js/08-prototypes/01-prototype-inheritance

1-js/08-prototypes/01-prototype-inheritance/article.md

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
# Prototypal inheritance
1+
# Прототипное наследование
22

3-
In programming, we often want to take something and extend it.
3+
В программировании мы часто хотим взять что-то и расширить.
44

5-
For instance, we have a `user` object with its properties and methods, and want to make `admin` and `guest` as slightly modified variants of it. We'd like to reuse what we have in `user`, not copy/reimplement its methods, just build a new object on top of it.
5+
Например, у нас есть объект `user` со своими свойствами и методами, и мы хотим создать объекты `admin` и `guest` как его слегка измененные варианты. Мы хотели бы повторно использовать то, что есть у объекта `user`, не копировать/переопределять его методы, а просто создать новый объект на его основе.
66

7-
*Prototypal inheritance* is a language feature that helps in that.
7+
*Прототипное наследование* — это возможность языка, которая помогает в этом.
88

99
## [[Prototype]]
1010

11-
In JavaScript, objects have a special hidden property `[[Prototype]]` (as named in the specification), that is either `null` or references another object. That object is called "a prototype":
11+
В JavaScript объекты имеют специальное скрытое свойство `[[Prototype]]` (так оно названо в спецификации), которое либо равно `null`, либо ссылается на другой объект. Этот объект называется "прототип":
1212

1313
![prototype](object-prototype-empty.png)
1414

15-
The prototype is a little bit "magical". When we want to read a property from `object`, and it's missing, JavaScript automatically takes it from the prototype. In programming, such thing is called "prototypal inheritance". Many cool language features and programming techniques are based on it.
15+
Этот `[[Prototype]]` дает нам немного "магии". Когда мы хотим прочитать свойство из `объекта`, а оно отсутствует, JavaScript автоматически берет его из прототипа. В программировании такой механизм называется "прототипным наследованием". Многие интересные возможности языка и техники программирования основываются на нем.
1616

17-
The property `[[Prototype]]` is internal and hidden, but there are many ways to set it.
17+
Свойство `[[Prototype]]` является внутренним и скрытым, но есть много способов задать его самостоятельно.
1818

19-
One of them is to use `__proto__`, like this:
19+
Одним из них является использование `__proto__`, например так:
2020

2121
```js run
2222
let animal = {
@@ -31,17 +31,17 @@ rabbit.__proto__ = animal;
3131
*/!*
3232
```
3333

34-
```smart header="`__proto__` is a historical getter/setter for `[[Prototype]]`"
35-
Please note that `__proto__` is *not the same* as `[[Prototype]]`. That's a getter/setter for it.
34+
```smart header="Свойство `__proto__` — исторически обусловленный геттер/сеттер для `[[Prototype]]`"
35+
Обратите внимание, что `__proto__` *не то же самое*, что `[[Prototype]]`. Это геттер/сеттер для него.
3636

37-
It exists for historical reasons, in modern language it is replaced with functions `Object.getPrototypeOf/Object.setPrototypeOf` that also get/set the prototype. We'll study the reasons for that and these functions later.
37+
Он существует по историческим причинам, в современном языке его заменяют функции `Object.getPrototypeOf/Object.setPrototypeOf`, которые также получают/устанавливают прототип. Мы рассмотрим причины этого и эти функции позже.
3838

39-
By the specification, `__proto__` must only be supported by browsers, but in fact all environments including server-side support it. For now, as `__proto__` notation is a little bit more intuitively obvious, we'll use it in the examples.
39+
По спецификации `__proto__` должен поддерживаться только браузерами, но на самом деле все среды, включая серверную, поддерживают его. На данный момент, поскольку нотация `__proto__` немного более понятна, мы будем использовать ее в примерах.
4040
```
4141
42-
If we look for a property in `rabbit`, and it's missing, JavaScript automatically takes it from `animal`.
42+
Если мы ищем свойство в `rabbit`, а оно отсутствует, JavaScript автоматически берет его из `animal`.
4343
44-
For instance:
44+
Например:
4545
4646
```js run
4747
let animal = {
@@ -55,24 +55,24 @@ let rabbit = {
5555
rabbit.__proto__ = animal; // (*)
5656
*/!*
5757
58-
// we can find both properties in rabbit now:
58+
// теперь мы можем найти оба свойства в rabbit:
5959
*!*
6060
alert( rabbit.eats ); // true (**)
6161
*/!*
6262
alert( rabbit.jumps ); // true
6363
```
6464

65-
Here the line `(*)` sets `animal` to be a prototype of `rabbit`.
65+
Здесь строка `(*)` устанавливает `animal` как прототип для `rabbit`.
6666

67-
Then, when `alert` tries to read property `rabbit.eats` `(**)`, it's not in `rabbit`, so JavaScript follows the `[[Prototype]]` reference and finds it in `animal` (look from the bottom up):
67+
Затем, когда `alert` пытается прочитать свойство `rabbit.eats` `(**)`, его нет в `rabbit`, поэтому JavaScript следует по ссылке `[[Prototype]]` и находит ее в `animal` (смотрите снизу вверх):
6868

6969
![](proto-animal-rabbit.png)
7070

71-
Here we can say that "`animal` is the prototype of `rabbit`" or "`rabbit` prototypically inherits from `animal`".
71+
Здесь мы можем сказать, что "`animal` является прототипом `rabbit`" или "`rabbit` прототипно наследуется от `animal`".
7272

73-
So if `animal` has a lot of useful properties and methods, then they become automatically available in `rabbit`. Such properties are called "inherited".
73+
Так что если у `animal` много полезных свойств и методов, то они автоматически становятся доступными у `rabbit`. Такие свойства называются "унаследованными".
7474

75-
If we have a method in `animal`, it can be called on `rabbit`:
75+
Если у нас есть метод в `animal`, он может быть вызван на `rabbit`:
7676

7777
```js run
7878
let animal = {
@@ -89,17 +89,17 @@ let rabbit = {
8989
__proto__: animal
9090
};
9191

92-
// walk is taken from the prototype
92+
// walk взят из прототипа
9393
*!*
9494
rabbit.walk(); // Animal walk
9595
*/!*
9696
```
9797

98-
The method is automatically taken from the prototype, like this:
98+
Метод автоматически берется из прототипа:
9999

100100
![](proto-animal-rabbit-walk.png)
101101

102-
The prototype chain can be longer:
102+
Цепочка прототипов может быть длиннее:
103103

104104

105105
```js run
@@ -124,33 +124,33 @@ let longEar = {
124124
*/!*
125125
};
126126

127-
// walk is taken from the prototype chain
127+
// walk взят из цепочки прототипов
128128
longEar.walk(); // Animal walk
129-
alert(longEar.jumps); // true (from rabbit)
129+
alert(longEar.jumps); // true (для rabbit)
130130
```
131131

132132
![](proto-animal-rabbit-chain.png)
133133

134-
There are actually only two limitations:
134+
На самом деле есть только два ограничения:
135135

136-
1. The references can't go in circles. JavaScript will throw an error if we try to assign `__proto__` in a circle.
137-
2. The value of `__proto__` can be either an object or `null`, other types (like primitives) are ignored.
136+
1. Ссылки не могут идти по кругу. JavaScript выдаст ошибку, если мы попытаемся назначить `__proto__` по кругу.
137+
2. Значение `__proto__` может быть как объектом, так и `null`, другие типы (например, примитивы) игнорируются.
138138

139-
Also it may be obvious, but still: there can be only one `[[Prototype]]`. An object may not inherit from two others.
139+
Это вполне очевидно, но все же: может быть только один `[[Prototype]]`. Объект не может наследоваться от двух других.
140140

141-
## Writing doesn't use prototype
141+
## Запись не использует прототип
142142

143-
The prototype is only used for reading properties.
143+
Прототип используется только для чтения свойств.
144144

145-
Write/delete operations work directly with the object.
145+
Операции записи/удаления работают напрямую с объектом.
146146

147-
In the example below, we assign its own `walk` method to `rabbit`:
147+
В приведенном ниже примере мы присваиваем `rabbit` собственный метод `walk`:
148148

149149
```js run
150150
let animal = {
151151
eats: true,
152152
walk() {
153-
/* this method won't be used by rabbit */
153+
/* этот метод не будет использоваться в rabbit */
154154
}
155155
};
156156

@@ -167,13 +167,13 @@ rabbit.walk = function() {
167167
rabbit.walk(); // Rabbit! Bounce-bounce!
168168
```
169169

170-
From now on, `rabbit.walk()` call finds the method immediately in the object and executes it, without using the prototype:
170+
Теперь вызов `rabbit.walk()` находит метод непосредственно в объекте и выполняет его, не используя прототип:
171171

172172
![](proto-animal-rabbit-walk-2.png)
173173

174-
That's for data properties only, not for accessors. If a property is a getter/setter, then it behaves like a function: getters/setters are looked up in the prototype.
174+
Это справедливо только для свойств данных, но не для аксессоров. Если свойство является геттером/сеттером, то оно ведет себя как функция: геттеры/сеттеры ищутся в прототипе.
175175

176-
For that reason `admin.fullName` works correctly in the code below:
176+
По этой причине `admin.fullName` работает корректно в приведенном ниже коде:
177177

178178
```js run
179179
let user = {
@@ -196,27 +196,27 @@ let admin = {
196196

197197
alert(admin.fullName); // John Smith (*)
198198

199-
// setter triggers!
199+
// срабатывает сеттер!
200200
admin.fullName = "Alice Cooper"; // (**)
201201
```
202202

203-
Here in the line `(*)` the property `admin.fullName` has a getter in the prototype `user`, so it is called. And in the line `(**)` the property has a setter in the prototype, so it is called.
203+
Здесь в строке `(*)` свойство `admin.fullName` имеет геттер в прототипе `user`, поэтому вызывается он. В строке `(**)` свойство также имеет сеттер в прототипе, который и будет вызван.
204204

205-
## The value of "this"
205+
## Значение "this"
206206

207-
An interesting question may arise in the example above: what's the value of `this` inside `set fullName(value)`? Where the properties `this.name` and `this.surname` are written: into `user` or `admin`?
207+
В приведенном выше примере может возникнуть интересный вопрос: каково значение `this` внутри `set fullName(value)`? Куда записаны свойства `this.name` и `this.surname`: в `user` или `admin`?
208208

209-
The answer is simple: `this` is not affected by prototypes at all.
209+
Ответ прост: прототипы никак не влияют на `this`.
210210

211-
**No matter where the method is found: in an object or its prototype. In a method call, `this` is always the object before the dot.**
211+
**Неважно, где находится метод: в объекте или его прототипе. В вызове метода, `this` — всегда объект перед точкой.**
212212

213-
So, the setter call `admin.fullName=` uses `admin` as `this`, not `user`.
213+
Таким образом, вызов сеттера `admin.fullName=` в качестве `this` использует `admin`, а не `user`.
214214

215-
That is actually a super-important thing, because we may have a big object with many methods and inherit from it. Then inherited objects can run its methods, and they will modify the state of these objects, not the big one.
215+
Это на самом деле очень важная деталь, потому что у нас может быть большой объект со множеством методов, от которого можно унаследоваться. Затем наследуемые объекты могут выполнять его методы, и они будут изменять состояние этих объектов, а не большого.
216216

217-
For instance, here `animal` represents a "method storage", and `rabbit` makes use of it.
217+
Например, здесь `animal` представляет собой "хранилище метода", и `rabbit` использует его.
218218

219-
The call `rabbit.sleep()` sets `this.isSleeping` on the `rabbit` object:
219+
Вызов `rabbit.sleep()` устанавливает `this.isSleeping` для объекта `rabbit`:
220220

221221
```js run
222222
// animal has methods
@@ -236,25 +236,25 @@ let rabbit = {
236236
__proto__: animal
237237
};
238238

239-
// modifies rabbit.isSleeping
239+
// модифицирует rabbit.isSleeping
240240
rabbit.sleep();
241241

242242
alert(rabbit.isSleeping); // true
243-
alert(animal.isSleeping); // undefined (no such property in the prototype)
243+
alert(animal.isSleeping); // undefined (нет такого свойства в прототипе)
244244
```
245245

246-
The resulting picture:
246+
Картинка с результатом:
247247

248248
![](proto-animal-rabbit-walk-3.png)
249249

250-
If we had other objects like `bird`, `snake` etc inheriting from `animal`, they would also gain access to methods of `animal`. But `this` in each method would be the corresponding object, evaluated at the call-time (before dot), not `animal`. So when we write data into `this`, it is stored into these objects.
250+
Если бы у нас были другие объекты, такие как `bird`, `snake` и т.д., унаследованные от `animal`, они также получили бы доступ к методам `animal`. Но `this` в каждом методе будет соответствовать объекту, на котором происходит вызов (до точки), а не `animal`. Поэтому, когда мы записываем данные в `this`, они сохраняются в этих объектах.
251251

252-
As a result, methods are shared, but the object state is not.
252+
В результате методы являются общими, а состояние объекта — нет.
253253

254-
## Summary
254+
## Итого
255255

256-
- In JavaScript, all objects have a hidden `[[Prototype]]` property that's either another object or `null`.
257-
- We can use `obj.__proto__` to access it (a historical getter/setter, there are other ways, to be covered soon).
258-
- The object referenced by `[[Prototype]]` is called a "prototype".
259-
- If we want to read a property of `obj` or call a method, and it doesn't exist, then JavaScript tries to find it in the prototype. Write/delete operations work directly on the object, they don't use the prototype (unless the property is actually a setter).
260-
- If we call `obj.method()`, and the `method` is taken from the prototype, `this` still references `obj`. So methods always work with the current object even if they are inherited.
256+
- В JavaScript все объекты имеют скрытое свойство `[[Prototype]]`, которое является либо другим объектом, либо `null`.
257+
- Мы можем использовать `obj.__ proto__` для доступа к нему (исторически обусловленный геттер/сеттер, есть другие способы, которые скоро будут рассмотрены).
258+
- Объект, на который ссылается `[[Prototype]]`, называется "прототипом".
259+
- Если мы хотим прочитать свойство `obj` или вызвать метод, которого не существует, тогда JavaScript попытается найти его в прототипе. Операции записи/удаления работают непосредственно с объектом, они не используют прототип (если свойство фактически не является сеттером).
260+
- Если мы вызываем `obj.method()`, а метод взят из прототипа, то `this` все равно ссылается на `obj`. Таким образом, методы всегда работают с текущим объектом, даже если они наследуются.

0 commit comments

Comments
 (0)