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/9-prototypes/5-class-inheritance/article.md
+22Lines changed: 22 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -331,4 +331,26 @@ var rabbit = new Rabbit('Кроль');
331
331
rabbit.run();
332
332
```
333
333
334
+
Такое наследование лучше функционального стиля, так как не дублирует методы в каждом объекте.
335
+
336
+
Кроме того, есть ещё неявное, но очень важное архитектурное отличие.
337
+
338
+
Зачастую вызов конструктора имеет какие-то побочные эффекты, например влияет на документ. Если конструктор родителя имеет какое-то поведение, которое нужно переопределить в потомке, то в функциональном стиле это невозможно.
339
+
340
+
Иначе говоря, в функциональном стиле в процессе создания `Rabbit` нужно обязательно вызывать `Animal.apply(this, arguments)`, чтобы получить методы родителя -- и если этот `Animal.apply` кроме добавления методов говорит: "Му-у-у!", то это проблема:
341
+
342
+
```js
343
+
functionAnimal() {
344
+
this.walk=function() { alert('walk')};
345
+
alert('Му-у-у!');
346
+
}
347
+
348
+
functionRabbit() {
349
+
Animal.apply(this, arguments); // как избавиться от мычания, но получить walk?
350
+
}
351
+
```
352
+
353
+
...Которой нет в прототипном подходе, потому что в процессе создания `new Rabbit` мы вовсе не обязаны вызывать конструктор родителя. Ведь методы находятся в прототипе.
354
+
355
+
Поэтому прототипный подход стоит предпочитать функциональному как более быстрый и универсальный. А что касается красоты синтаксиса -- она сильно лучше в новом стандарте ES6, которым можно пользоваться уже сейчас, если взять транслятор [6to5](http://6to5.org/).
Когда мы работаем с внешними данными, возможны самые разные ошибки.
87
-
88
-
Создание иерархии ошибок вносит порядок в происходящее, а `instanceof` внутри `try..catch` позволяет легко понять, что за ошибка произошла и обработать, либо пробросить её дальше.
89
-
90
-
Для примера создадим функцию `readUser(json)`, которая будет разбирать JSON с данными посетителя. Мы его получаем с сервера -- может, нашего, а может -- чужого, в общем -- желательно проверить на ошибки. А может, это даже и не JSON, а какие-то другие данные -- не важно, для наглядности поработаем с JSON.
91
-
92
-
Пример правильного JSON: `{ "name": "Вася", "age": 30 }`.
93
-
94
-
Функция `readUser` должна бросать исключение в случаях, когда:
95
-
96
-
<ol>
97
-
<li>В JSON синтаксическая ошибка, то есть "падает" вызов `JSON.parse`.</li>
98
-
<li>В получившемся объекте нет свойства `name` или `age`.</li>
99
-
<li>Свойство `age` (возраст) -- не число.</li>
100
-
</ol>
101
-
102
-
Для каждого из этих типов ошибок сделаем отдельный класс -- это поможет позже легко идентифицировать произошедшее:
103
-
104
-
<ol>
105
-
<li>`SyntaxError` -- ошибка "что-то не так в данных", встроенный класс, ошибка такого типа генерируется как раз `JSON.parse`.</li>
106
-
<li>`PropertyRequiredError` -- ошибка "нет свойства", будет наследовать от `SyntaxError`, так как является подвидом синтаксической ошибки.</li>
107
-
<li>`FormatError` -- "ошибка форматирования", тоже наследник `SyntaxError`.</li>
Понятное дело, эти классы ошибок имеют общий характер и могут использоваться не только в данной конкретной функции, но и в других местах кода -- при обработке любых данных.
131
-
132
-
**У разных типов ошибок могут быть разные конструкторы, разные дополнительные свойства, которые позволят в дальнейшем удобно работать с ошибкой.**
133
-
134
-
В коде выше обратите внимание на `PropertyRequiredError` -- конструтор этой ошибки получает отсутствующее свойство и сохраняет его в дополнительном свойстве `property`, в дополнение к стандартному `message`. В дальнейшем, для особой обработки этой ошибки, его легко можно будет получить.
// в данном месте кода возможны анонимы, ошибка поправима
185
-
user[e.property] ="Аноним";
186
-
} else {
187
-
alert(e.message);
188
-
}
189
-
} elseif (e instanceofSyntaxError) {
190
-
alert("Ошибка в данных: "+e.message);
191
-
} else {
192
-
throw e; // неизвестная ошибка, не знаю что с ней делать
193
-
}
194
-
*/!*
195
-
}
196
-
```
197
-
198
-
Обратим внимание -- в данном конкретном месте кода мы допускаем анонимных посетителей, поэтому в случае, если отсутствует `name` -- исправляем эту ошибку. Мы можем легко это сделать, благодаря наличию у `PropertyRequiredError` дополнительного (по сравнению со стандартными ошибками) свойства `property`.
199
-
200
-
**Для проверки, какая именно ошибка произошла, вместо `e.name` используется `instanceof`.**
201
-
202
-
Это позволяет как выделить какие-то отдельные типы ошибок (`e instanceof PropertyRequiredError`), так и проверить общий тип, с которым мы умеем работать, без оглядки на его детали (`e instanceof SyntaxError`).
203
-
204
-
Благодаря `instanceof` мы получили удобную поддержку иерархии ошибок, с возможностью в любой момент добавить новые классы, понятным кодом и предсказуемым поведением.
205
-
206
84
## Итого
207
85
208
86
<ul>
209
87
<li>Оператор `obj instanceof Func` проверяет тот факт, что `obj` является результатом вызова `new Func`. Он учитывает цепочку `__proto__`, поэтому наследование поддерживается.</li>
210
88
<li>Оператор `instanceof` не сможет проверить тип значения, если объект создан в одном окне/фрейме, а проверяется в другом. Это потому, что в каждом окне -- своя иерархия объектов. Для точной проверки типов встроенных объектов можно использовать свойство `[[Class]]`.</li>
211
-
<li>Оператор `instanceof` особенно востребован в случаях, когда мы работаем с иерархиями классов. Это наилучший способ проверить принадлежность тому или иному классу с учётом наследования.</li>
212
89
</ul>
90
+
91
+
Оператор `instanceof` особенно востребован в случаях, когда мы работаем с иерархиями классов. Это наилучший способ проверить принадлежность тому или иному классу с учётом наследования.
0 commit comments