Skip to content

Commit f702e3d

Browse files
committed
renovations
1 parent 56b567a commit f702e3d

21 files changed

Lines changed: 332 additions & 726 deletions

File tree

1-js/2-first-steps/13-types-conversion/article.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ var a = +"123"; // 123
5151
var a = Number("123"); // 123, тот же эффект
5252
```
5353

54-
<table class="bordered">
54+
<table>
5555
<tr><th>Значение</th><th>Преобразуется в...</th></tr>
5656
<tr><td>`undefined`</td><td>`NaN`</td></tr>
5757
<tr><td>`null`</td><td>`0`</td></tr>

1-js/2-first-steps/4-variables/variable.svg

Lines changed: 17 additions & 21 deletions
Loading

1-js/2-first-steps/9-bitwise-operators/3-bitwise-symmetry/solution.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Посмотрим, можно ли поменять местами биты слева и справа.
44

55
Например, таблица истинности для `^`:
6-
<table class="bordered">
6+
<table>
77
<tr>
88
<th>`a`</th>
99
<th>`b`</th>

1-js/4-data-structures/9-array-iteration/article.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ alert(result); // 15
149149

150150
В виде таблицы где каждая строка -- вызов функции на очередном элементе массива:
151151

152-
<table class="bordered">
152+
<table>
153153
<thead>
154154
<tr>
155155
<th></th>

1-js/9-prototypes/5-class-inheritance/article.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,4 +331,26 @@ var rabbit = new Rabbit('Кроль');
331331
rabbit.run();
332332
```
333333

334+
Такое наследование лучше функционального стиля, так как не дублирует методы в каждом объекте.
335+
336+
Кроме того, есть ещё неявное, но очень важное архитектурное отличие.
337+
338+
Зачастую вызов конструктора имеет какие-то побочные эффекты, например влияет на документ. Если конструктор родителя имеет какое-то поведение, которое нужно переопределить в потомке, то в функциональном стиле это невозможно.
339+
340+
Иначе говоря, в функциональном стиле в процессе создания `Rabbit` нужно обязательно вызывать `Animal.apply(this, arguments)`, чтобы получить методы родителя -- и если этот `Animal.apply` кроме добавления методов говорит: "Му-у-у!", то это проблема:
341+
342+
```js
343+
function Animal() {
344+
this.walk = function() { alert('walk')};
345+
alert('Му-у-у!');
346+
}
347+
348+
function Rabbit() {
349+
Animal.apply(this, arguments); // как избавиться от мычания, но получить walk?
350+
}
351+
```
352+
353+
...Которой нет в прототипном подходе, потому что в процессе создания `new Rabbit` мы вовсе не обязаны вызывать конструктор родителя. Ведь методы находятся в прототипе.
354+
355+
Поэтому прототипный подход стоит предпочитать функциональному как более быстрый и универсальный. А что касается красоты синтаксиса -- она сильно лучше в новом стандарте ES6, которым можно пользоваться уже сейчас, если взять транслятор [6to5](http://6to5.org/).
334356

1-js/9-prototypes/6-instanceof/article.md

Lines changed: 2 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -81,132 +81,11 @@ alert( rabbit instanceof Rabbit ); // false
8181
[/warn]
8282

8383

84-
## instanceof + наследование + try..catch = ♡
85-
86-
Когда мы работаем с внешними данными, возможны самые разные ошибки.
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>
108-
</ol>
109-
110-
Вот ошибки в JS:
111-
112-
```js
113-
function PropertyRequiredError(property) {
114-
*!*
115-
this.property = property;
116-
this.message = "Отсутствует свойство " + property;
117-
*/!*
118-
this.name = 'PropertyRequired';
119-
}
120-
PropertyRequiredError.prototype = Object.create(SyntaxError.prototype);
121-
122-
123-
function FormatError(message) {
124-
this.message = message;
125-
this.name = 'FormatError';
126-
}
127-
FormatError.prototype = Object.create(SyntaxError.prototype);
128-
```
129-
130-
Понятное дело, эти классы ошибок имеют общий характер и могут использоваться не только в данной конкретной функции, но и в других местах кода -- при обработке любых данных.
131-
132-
**У разных типов ошибок могут быть разные конструкторы, разные дополнительные свойства, которые позволят в дальнейшем удобно работать с ошибкой.**
133-
134-
В коде выше обратите внимание на `PropertyRequiredError` -- конструтор этой ошибки получает отсутствующее свойство и сохраняет его в дополнительном свойстве `property`, в дополнение к стандартному `message`. В дальнейшем, для особой обработки этой ошибки, его легко можно будет получить.
135-
136-
Код ниже -- полная реализация `readUser`:
137-
138-
```js
139-
function PropertyRequiredError(property) {
140-
this.property = property;
141-
this.message = "Отсутствует свойство " + property;
142-
this.name = 'PropertyRequired';
143-
}
144-
PropertyRequiredError.prototype = Object.create(SyntaxError.prototype);
145-
146-
147-
function FormatError(message) {
148-
this.message = message;
149-
this.name = 'FormatError';
150-
}
151-
FormatError.prototype = Object.create(SyntaxError.prototype);
152-
153-
154-
function readUser(data) {
155-
156-
var user = JSON.parse(data);
157-
158-
validateUser(user);
159-
160-
return user;
161-
}
162-
163-
function validateUser(user) {
164-
165-
if (!user.age) {
166-
throw new PropertyRequiredError("age");
167-
}
168-
if (typeof user.age != "number") {
169-
throw new FormatError("Возраст - не число");
170-
}
171-
172-
if (!user.name) {
173-
throw new PropertyRequiredError("name");
174-
}
175-
176-
}
177-
178-
try {
179-
readUser('{ "name": "Вася", "age": "unknown" }');
180-
} catch (e) {
181-
*!*
182-
if (e instanceof PropertyRequiredError) {
183-
if (e.property == 'name') {
184-
// в данном месте кода возможны анонимы, ошибка поправима
185-
user[e.property] = "Аноним";
186-
} else {
187-
alert(e.message);
188-
}
189-
} else if (e instanceof SyntaxError) {
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-
20684
## Итого
20785

20886
<ul>
20987
<li>Оператор `obj instanceof Func` проверяет тот факт, что `obj` является результатом вызова `new Func`. Он учитывает цепочку `__proto__`, поэтому наследование поддерживается.</li>
21088
<li>Оператор `instanceof` не сможет проверить тип значения, если объект создан в одном окне/фрейме, а проверяется в другом. Это потому, что в каждом окне -- своя иерархия объектов. Для точной проверки типов встроенных объектов можно использовать свойство `[[Class]]`.</li>
211-
<li>Оператор `instanceof` особенно востребован в случаях, когда мы работаем с иерархиями классов. Это наилучший способ проверить принадлежность тому или иному классу с учётом наследования.</li>
21289
</ul>
90+
91+
Оператор `instanceof` особенно востребован в случаях, когда мы работаем с иерархиями классов. Это наилучший способ проверить принадлежность тому или иному классу с учётом наследования.

0 commit comments

Comments
 (0)