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
+16-17Lines changed: 16 additions & 17 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,9 +12,9 @@
12
12
13
13

14
14
15
-
Этот `[[Prototype]]`даёт нам немного "магии". Когда мы хотим прочитать свойство из `объекта`, а оно отсутствует, JavaScript автоматически берет его из прототипа. В программировании такой механизм называется "прототипным наследованием". Многие интересные возможности языка и техники программирования основываются на нем.
15
+
Прототип даёт нам немного "магии". Когда мы хотим прочитать свойство из `object`, а оно отсутствует, JavaScript автоматически берет его из прототипа. В программировании такой механизм называется "прототипным наследованием". Многие интересные возможности языка и техники программирования основываются на нем.
16
16
17
-
Свойство `[[Prototype]]` является внутренним и скрытым, но есть много способов задать его самостоятельно.
17
+
Свойство `[[Prototype]]` является внутренним и скрытым, но есть много способов задать его.
18
18
19
19
Одним из них является использование `__proto__`, например так:
20
20
@@ -36,7 +36,7 @@ rabbit.__proto__ = animal;
36
36
37
37
Он существует по историческим причинам, в современном языке его заменяют функции `Object.getPrototypeOf/Object.setPrototypeOf`, которые также получают/устанавливают прототип. Мы рассмотрим причины этого и эти функции позже.
38
38
39
-
По спецификации `__proto__` должен поддерживаться только браузерами, но на самом деле все среды, включая серверную, поддерживают его. На данный момент, поскольку нотация `__proto__` немного более понятна, мы будем использовать её в примерах.
39
+
По спецификации `__proto__` должен поддерживаться только браузерами, но по факту все среды, включая серверную, поддерживают его. Далее мы будем в примерах использовать `__proto__`, так как это самый короткий и интуитивно понятный способ установки и чтения прототипа.
40
40
```
41
41
42
42
Если мы ищем свойство в `rabbit`, а оно отсутствует, JavaScript автоматически берет его из `animal`.
@@ -68,7 +68,7 @@ alert( rabbit.jumps ); // true
68
68
69
69

70
70
71
-
Здесь мы можем сказать, что "`animal` является прототипом `rabbit`" или "`rabbit` прототипно наследуется от `animal`".
71
+
Здесь мы можем сказать, что "`animal` является прототипом `rabbit`" или "`rabbit` прототипно наследует от `animal`".
72
72
73
73
Так что если у `animal` много полезных свойств и методов, то они автоматически становятся доступными у `rabbit`. Такие свойства называются "унаследованными".
74
74
@@ -101,7 +101,6 @@ rabbit.walk(); // Animal walk
101
101
102
102
Цепочка прототипов может быть длиннее:
103
103
104
-
105
104
```js run
106
105
let animal = {
107
106
eats:true,
@@ -131,12 +130,12 @@ alert(longEar.jumps); // true (для rabbit)
131
130
132
131

133
132
134
-
На самом деле есть только два ограничения:
133
+
Есть только два ограничения:
135
134
136
135
1. Ссылки не могут идти по кругу. JavaScript выдаст ошибку, если мы попытаемся назначить `__proto__` по кругу.
137
-
2. Значение `__proto__` может быть как объектом, так и `null`, другие типы (например, примитивы) игнорируются.
136
+
2. Значение `__proto__` может быть объектом или `null`. Другие типы игнорируются.
138
137
139
-
Это вполне очевидно, но все же: может быть только один `[[Prototype]]`. Объект не может наследоваться от двух других.
138
+
Это вполне очевидно, но все же: может быть только один `[[Prototype]]`. Объект не может наследовать от двух других.
Это справедливо только для свойств данных, но не для аксессоров. Если свойство является геттером/сеттером, то оно ведёт себя как функция: геттеры/сеттеры ищутся в прототипе.
173
+
Свойства-акссессоры - исключение, так как запись в него обрабатывается функцией-сеттером. То есть, это, фактически, вызов функции.
175
174
176
175
По этой причине `admin.fullName` работает корректно в приведённом ниже коде:
**Неважно, где находится метод: в объекте или его прототипе. В вызове метода,`this` — всегда объект перед точкой.**
210
+
**Неважно, где находится метод: в объекте или его прототипе. При вызове метода `this` — всегда объект перед точкой.**
212
211
213
212
Таким образом, вызов сеттера `admin.fullName=` в качестве `this` использует `admin`, а не `user`.
214
213
215
-
Это на самом деле очень важная деталь, потому что у нас может быть большой объект со множеством методов, от которого можно унаследоваться. Затем наследуемые объекты могут выполнять его методы, и они будут изменять состояние этих объектов, а не большого.
214
+
Это на самом деле очень важная деталь, потому что у нас может быть большой объект со множеством методов, от которого можно наследовать. Затем наследущие объекты могут вызывать его методы, но они будут изменять состояние этих объектов, а не большого.
216
215
217
-
Например, здесь `animal` представляет собой "хранилище метода", и `rabbit` использует его.
216
+
Например, здесь `animal` представляет собой "хранилище методов", и `rabbit` использует его.
218
217
219
218
Вызов `rabbit.sleep()` устанавливает `this.isSleeping` для объекта `rabbit`:
220
219
@@ -247,11 +246,11 @@ alert(animal.isSleeping); // undefined (нет такого свойства в
247
246
248
247

249
248
250
-
Если бы у нас были другие объекты, такие как `bird`, `snake` и т.д., унаследованные от `animal`, они также получили бы доступ к методам `animal`. Но `this`в каждом методе будет соответствовать объекту, на котором происходит вызов (до точки), а не `animal`. Поэтому, когда мы записываем данные в `this`, они сохраняются в этих объектах.
249
+
Если бы у нас были другие объекты, такие как `bird`, `snake` и т.д., унаследованные от `animal`, они также получили бы доступ к методам `animal`. Но `this`при вызове каждого метода будет соответствовать объекту, на котором происходит вызов (перед точкой), а не `animal`. Поэтому, когда мы записываем данные в `this`, они сохраняются в этих объектах.
251
250
252
251
В результате методы являются общими, а состояние объекта — нет.
253
252
254
-
## Цикл for..in
253
+
## Цикл for..in
255
254
256
255
Цикл `for..in` проходит не только во собственным, но и по унаследованным свойствам объекта.
257
256
@@ -313,8 +312,8 @@ for(let prop in rabbit) {
313
312
314
313
Ответ простой: оно не перечислимо. То есть, у него внутренний флаг `enumerable` стоит `false`, как и у других свойств `Object.prototype`. Поэтому оно и не появляется в цикле.
315
314
316
-
```smart header="Все остальные перебирающие методы игнорируют унаследованные свойства"
317
-
Все остальные методы, получающие ключи/значения, такие как `Object.keys`, `Object.values` и другие - игнорируют унаследованные свойства.
315
+
```smart header="Почти все остальные методы получения ключей/значений игнорируют унаследованные свойства"
316
+
Почти все остальные методы, получающие ключи/значения, такие как `Object.keys`, `Object.values` и другие - игнорируют унаследованные свойства.
318
317
319
318
Они учитывают только свойства самого объекта, не его прототипа.
320
319
```
@@ -324,7 +323,7 @@ for(let prop in rabbit) {
324
323
- В JavaScript все объекты имеют скрытое свойство `[[Prototype]]`, которое является либо другим объектом, либо `null`.
325
324
- Мы можем использовать `obj.__ proto__` для доступа к нему (исторически обусловленный геттер/сеттер, есть другие способы, которые скоро будут рассмотрены).
326
325
- Объект, на который ссылается `[[Prototype]]`, называется "прототипом".
327
-
- Если мы хотим прочитать свойство `obj` или вызвать метод, которого не существует, тогда JavaScript попытается найти его в прототипе.
326
+
- Если мы хотим прочитать свойство `obj` или вызвать метод, которого не существует, тогда JavaScript попытается найти его в прототипе.
328
327
- Операции записи/удаления работают непосредственно с объектом, они не используют прототип (если это обычное свойство, а не не сеттер).
329
328
- Если мы вызываем `obj.method()`, а метод взят из прототипа, то `this` все равно ссылается на `obj`. Таким образом, методы всегда работают с текущим объектом, даже если они наследуются.
330
329
- Цикл `for..in` перебирает как свои, так и унаследованные свойства. Остальные методы получения ключей/значений работают только с самим объектом.
0 commit comments