You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 1-js/08-prototypes/01-prototype-inheritance/article.md
+58-58Lines changed: 58 additions & 58 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,22 +1,22 @@
1
-
# Prototypal inheritance
1
+
# Прототипное наследование
2
2
3
-
In programming, we often want to take something and extend it.
3
+
В программировании мы часто хотим взять что-то и расширить.
4
4
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`, не копировать/переопределять его методы, а просто создать новый объект на его основе.
6
6
7
-
*Prototypal inheritance* is a language feature that helps in that.
7
+
*Прототипное наследование* — это возможность языка, которая помогает в этом.
8
8
9
9
## [[Prototype]]
10
10
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`, либо ссылается на другой объект. Этот объект называется "прототип":
12
12
13
13

14
14
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 автоматически берет его из прототипа. В программировании такой механизм называется "прототипным наследованием". Многие интересные возможности языка и техники программирования основываются на нем.
16
16
17
-
The property `[[Prototype]]`is internal and hidden, but there are many ways to set it.
17
+
Свойство `[[Prototype]]`является внутренним и скрытым, но есть много способов задать его самостоятельно.
18
18
19
-
One of them is to use `__proto__`, like this:
19
+
Одним из них является использование `__proto__`, например так:
20
20
21
21
```js run
22
22
let animal = {
@@ -31,17 +31,17 @@ rabbit.__proto__ = animal;
31
31
*/!*
32
32
```
33
33
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]]`. Это геттер/сеттер для него.
36
36
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`, которые также получают/устанавливают прототип. Мы рассмотрим причины этого и эти функции позже.
38
38
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__`немного более понятна, мы будем использовать ее в примерах.
40
40
```
41
41
42
-
If we look for a property in `rabbit`, and it's missing, JavaScript automatically takes it from `animal`.
42
+
Если мы ищем свойство в `rabbit`, а оно отсутствует, JavaScript автоматически берет его из `animal`.
43
43
44
-
For instance:
44
+
Например:
45
45
46
46
```js run
47
47
let animal = {
@@ -55,24 +55,24 @@ let rabbit = {
55
55
rabbit.__proto__ = animal; // (*)
56
56
*/!*
57
57
58
-
// we can find both properties in rabbit now:
58
+
// теперь мы можем найти оба свойства в rabbit:
59
59
*!*
60
60
alert( rabbit.eats ); // true (**)
61
61
*/!*
62
62
alert( rabbit.jumps ); // true
63
63
```
64
64
65
-
Here the line `(*)`sets`animal`to be a prototype of`rabbit`.
65
+
Здесь строка `(*)`устанавливает`animal`как прототип для`rabbit`.
66
66
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` (смотрите снизу вверх):
68
68
69
69

70
70
71
-
Here we can say that "`animal`is the prototype of `rabbit`" or "`rabbit`prototypically inherits from`animal`".
71
+
Здесь мы можем сказать, что "`animal`является прототипом `rabbit`" или "`rabbit`прототипно наследуется от`animal`".
72
72
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`. Такие свойства называются "унаследованными".
74
74
75
-
If we have a method in`animal`, it can be called on`rabbit`:
75
+
Если у нас есть метод в`animal`, он может быть вызван на`rabbit`:
76
76
77
77
```js run
78
78
let animal = {
@@ -89,17 +89,17 @@ let rabbit = {
89
89
__proto__: animal
90
90
};
91
91
92
-
// walk is taken from the prototype
92
+
// walk взят из прототипа
93
93
*!*
94
94
rabbit.walk(); // Animal walk
95
95
*/!*
96
96
```
97
97
98
-
The method is automatically taken from the prototype, like this:
98
+
Метод автоматически берется из прототипа:
99
99
100
100

101
101
102
-
The prototype chain can be longer:
102
+
Цепочка прототипов может быть длиннее:
103
103
104
104
105
105
```js run
@@ -124,33 +124,33 @@ let longEar = {
124
124
*/!*
125
125
};
126
126
127
-
// walk is taken from the prototype chain
127
+
// walk взят из цепочки прототипов
128
128
longEar.walk(); // Animal walk
129
-
alert(longEar.jumps); // true (from rabbit)
129
+
alert(longEar.jumps); // true (для rabbit)
130
130
```
131
131
132
132

133
133
134
-
There are actually only two limitations:
134
+
На самом деле есть только два ограничения:
135
135
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`, другие типы (например, примитивы) игнорируются.
138
138
139
-
Also it may be obvious, but still: there can be only one `[[Prototype]]`. An object may not inherit from two others.
139
+
Это вполне очевидно, но все же: может быть только один `[[Prototype]]`. Объект не может наследоваться от двух других.
140
140
141
-
## Writing doesn't use prototype
141
+
## Запись не использует прототип
142
142
143
-
The prototype is only used for reading properties.
143
+
Прототип используется только для чтения свойств.
144
144
145
-
Write/delete operations work directly with the object.
145
+
Операции записи/удаления работают напрямую с объектом.
146
146
147
-
In the example below, we assign its own `walk` method to `rabbit`:
147
+
В приведенном ниже примере мы присваиваем `rabbit` собственный метод `walk`:
148
148
149
149
```js run
150
150
let animal = {
151
151
eats:true,
152
152
walk() {
153
-
/*this method won't be used by rabbit */
153
+
/*этот метод не будет использоваться в rabbit */
154
154
}
155
155
};
156
156
@@ -167,13 +167,13 @@ rabbit.walk = function() {
167
167
rabbit.walk(); // Rabbit! Bounce-bounce!
168
168
```
169
169
170
-
From now on, `rabbit.walk()`call finds the method immediately in the object and executes it, without using the prototype:
170
+
Теперь вызов `rabbit.walk()`находит метод непосредственно в объекте и выполняет его, не используя прототип:
171
171
172
172

173
173
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
+
Это справедливо только для свойств данных, но не для аксессоров. Если свойство является геттером/сеттером, то оно ведет себя как функция: геттеры/сеттеры ищутся в прототипе.
175
175
176
-
For that reason`admin.fullName`works correctly in the code below:
176
+
По этой причине`admin.fullName`работает корректно в приведенном ниже коде:
177
177
178
178
```js run
179
179
let user = {
@@ -196,27 +196,27 @@ let admin = {
196
196
197
197
alert(admin.fullName); // John Smith (*)
198
198
199
-
//setter triggers!
199
+
//срабатывает сеттер!
200
200
admin.fullName="Alice Cooper"; // (**)
201
201
```
202
202
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`, поэтому вызывается он. В строке `(**)`свойство также имеет сеттер в прототипе, который и будет вызван.
204
204
205
-
## The value of "this"
205
+
## Значение "this"
206
206
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`?
208
208
209
-
The answer is simple: `this` is not affected by prototypes at all.
209
+
Ответ прост: прототипы никак не влияют на `this`.
210
210
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`— всегда объект перед точкой.**
212
212
213
-
So, the setter call `admin.fullName=`uses `admin` as `this`, not`user`.
213
+
Таким образом, вызов сеттера `admin.fullName=`в качестве `this` использует `admin`, а не`user`.
214
214
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
+
Это на самом деле очень важная деталь, потому что у нас может быть большой объект со множеством методов, от которого можно унаследоваться. Затем наследуемые объекты могут выполнять его методы, и они будут изменять состояние этих объектов, а не большого.
216
216
217
-
For instance, here`animal`represents a "method storage", and`rabbit`makes use of it.
217
+
Например, здесь`animal`представляет собой "хранилище метода", и`rabbit`использует его.
218
218
219
-
The call `rabbit.sleep()`sets`this.isSleeping`on the`rabbit` object:
alert(animal.isSleeping); // undefined (no such property in the prototype)
243
+
alert(animal.isSleeping); // undefined (нет такого свойства в прототипе)
244
244
```
245
245
246
-
The resulting picture:
246
+
Картинка с результатом:
247
247
248
248

249
249
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`, они сохраняются в этих объектах.
251
251
252
-
As a result, methods are shared, but the object state is not.
252
+
В результате методы являются общими, а состояние объекта — нет.
253
253
254
-
## Summary
254
+
## Итого
255
255
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