diff --git a/1-js/2-first-steps/13-types-conversion/article.md b/1-js/2-first-steps/13-types-conversion/article.md
index 8526f07d..f22b20e1 100644
--- a/1-js/2-first-steps/13-types-conversion/article.md
+++ b/1-js/2-first-steps/13-types-conversion/article.md
@@ -51,7 +51,7 @@ var a = +"123"; // 123
var a = Number("123"); // 123, тот же эффект
```
-
+
Значение Преобразуется в...
`undefined` `NaN`
`null` `0`
diff --git a/1-js/2-first-steps/4-variables/variable.svg b/1-js/2-first-steps/4-variables/variable.svg
index 041ceea9..f2ac40a4 100644
--- a/1-js/2-first-steps/4-variables/variable.svg
+++ b/1-js/2-first-steps/4-variables/variable.svg
@@ -1,28 +1,24 @@
-
+
- Diagrams
+ variable
Created with Sketch.
-
-
-
-
-
-
-
-
-
-
- "Hello!"
-
-
-
-
-
-
-
- message
+
+
+
+
+
+
+
+
+ "Hello!"
+
+
+
+
+
+ Message
diff --git a/1-js/2-first-steps/9-bitwise-operators/3-bitwise-symmetry/solution.md b/1-js/2-first-steps/9-bitwise-operators/3-bitwise-symmetry/solution.md
index abc0d296..737c32cc 100644
--- a/1-js/2-first-steps/9-bitwise-operators/3-bitwise-symmetry/solution.md
+++ b/1-js/2-first-steps/9-bitwise-operators/3-bitwise-symmetry/solution.md
@@ -3,7 +3,7 @@
Посмотрим, можно ли поменять местами биты слева и справа.
Например, таблица истинности для `^`:
-
+
`a`
`b`
diff --git a/1-js/4-data-structures/9-array-iteration/article.md b/1-js/4-data-structures/9-array-iteration/article.md
index bf02ed2b..37392b0c 100644
--- a/1-js/4-data-structures/9-array-iteration/article.md
+++ b/1-js/4-data-structures/9-array-iteration/article.md
@@ -149,7 +149,7 @@ alert(result); // 15
В виде таблицы где каждая строка -- вызов функции на очередном элементе массива:
-
+
diff --git a/1-js/9-prototypes/5-class-inheritance/article.md b/1-js/9-prototypes/5-class-inheritance/article.md
index c4d13e09..3cf4d4d1 100644
--- a/1-js/9-prototypes/5-class-inheritance/article.md
+++ b/1-js/9-prototypes/5-class-inheritance/article.md
@@ -331,4 +331,26 @@ var rabbit = new Rabbit('Кроль');
rabbit.run();
```
+Такое наследование лучше функционального стиля, так как не дублирует методы в каждом объекте.
+
+Кроме того, есть ещё неявное, но очень важное архитектурное отличие.
+
+Зачастую вызов конструктора имеет какие-то побочные эффекты, например влияет на документ. Если конструктор родителя имеет какое-то поведение, которое нужно переопределить в потомке, то в функциональном стиле это невозможно.
+
+Иначе говоря, в функциональном стиле в процессе создания `Rabbit` нужно обязательно вызывать `Animal.apply(this, arguments)`, чтобы получить методы родителя -- и если этот `Animal.apply` кроме добавления методов говорит: "Му-у-у!", то это проблема:
+
+```js
+function Animal() {
+ this.walk = function() { alert('walk')};
+ alert('Му-у-у!');
+}
+
+function Rabbit() {
+ Animal.apply(this, arguments); // как избавиться от мычания, но получить walk?
+}
+```
+
+...Которой нет в прототипном подходе, потому что в процессе создания `new Rabbit` мы вовсе не обязаны вызывать конструктор родителя. Ведь методы находятся в прототипе.
+
+Поэтому прототипный подход стоит предпочитать функциональному как более быстрый и универсальный. А что касается красоты синтаксиса -- она сильно лучше в новом стандарте ES6, которым можно пользоваться уже сейчас, если взять транслятор [6to5](http://6to5.org/).
diff --git a/1-js/9-prototypes/6-instanceof/article.md b/1-js/9-prototypes/6-instanceof/article.md
index dff06ccd..b8d048a8 100644
--- a/1-js/9-prototypes/6-instanceof/article.md
+++ b/1-js/9-prototypes/6-instanceof/article.md
@@ -81,132 +81,11 @@ alert( rabbit instanceof Rabbit ); // false
[/warn]
-## instanceof + наследование + try..catch = ♡
-
-Когда мы работаем с внешними данными, возможны самые разные ошибки.
-
-Создание иерархии ошибок вносит порядок в происходящее, а `instanceof` внутри `try..catch` позволяет легко понять, что за ошибка произошла и обработать, либо пробросить её дальше.
-
-Для примера создадим функцию `readUser(json)`, которая будет разбирать JSON с данными посетителя. Мы его получаем с сервера -- может, нашего, а может -- чужого, в общем -- желательно проверить на ошибки. А может, это даже и не JSON, а какие-то другие данные -- не важно, для наглядности поработаем с JSON.
-
-Пример правильного JSON: `{ "name": "Вася", "age": 30 }`.
-
-Функция `readUser` должна бросать исключение в случаях, когда:
-
-
-В JSON синтаксическая ошибка, то есть "падает" вызов `JSON.parse`.
-В получившемся объекте нет свойства `name` или `age`.
-Свойство `age` (возраст) -- не число.
-
-
-Для каждого из этих типов ошибок сделаем отдельный класс -- это поможет позже легко идентифицировать произошедшее:
-
-
-`SyntaxError` -- ошибка "что-то не так в данных", встроенный класс, ошибка такого типа генерируется как раз `JSON.parse`.
-`PropertyRequiredError` -- ошибка "нет свойства", будет наследовать от `SyntaxError`, так как является подвидом синтаксической ошибки.
-`FormatError` -- "ошибка форматирования", тоже наследник `SyntaxError`.
-
-
-Вот ошибки в JS:
-
-```js
-function PropertyRequiredError(property) {
-*!*
- this.property = property;
- this.message = "Отсутствует свойство " + property;
-*/!*
- this.name = 'PropertyRequired';
-}
-PropertyRequiredError.prototype = Object.create(SyntaxError.prototype);
-
-
-function FormatError(message) {
- this.message = message;
- this.name = 'FormatError';
-}
-FormatError.prototype = Object.create(SyntaxError.prototype);
-```
-
-Понятное дело, эти классы ошибок имеют общий характер и могут использоваться не только в данной конкретной функции, но и в других местах кода -- при обработке любых данных.
-
-**У разных типов ошибок могут быть разные конструкторы, разные дополнительные свойства, которые позволят в дальнейшем удобно работать с ошибкой.**
-
-В коде выше обратите внимание на `PropertyRequiredError` -- конструтор этой ошибки получает отсутствующее свойство и сохраняет его в дополнительном свойстве `property`, в дополнение к стандартному `message`. В дальнейшем, для особой обработки этой ошибки, его легко можно будет получить.
-
-Код ниже -- полная реализация `readUser`:
-
-```js
-function PropertyRequiredError(property) {
- this.property = property;
- this.message = "Отсутствует свойство " + property;
- this.name = 'PropertyRequired';
-}
-PropertyRequiredError.prototype = Object.create(SyntaxError.prototype);
-
-
-function FormatError(message) {
- this.message = message;
- this.name = 'FormatError';
-}
-FormatError.prototype = Object.create(SyntaxError.prototype);
-
-
-function readUser(data) {
-
- var user = JSON.parse(data);
-
- validateUser(user);
-
- return user;
-}
-
-function validateUser(user) {
-
- if (!user.age) {
- throw new PropertyRequiredError("age");
- }
- if (typeof user.age != "number") {
- throw new FormatError("Возраст - не число");
- }
-
- if (!user.name) {
- throw new PropertyRequiredError("name");
- }
-
-}
-
-try {
- readUser('{ "name": "Вася", "age": "unknown" }');
-} catch (e) {
-*!*
- if (e instanceof PropertyRequiredError) {
- if (e.property == 'name') {
- // в данном месте кода возможны анонимы, ошибка поправима
- user[e.property] = "Аноним";
- } else {
- alert(e.message);
- }
- } else if (e instanceof SyntaxError) {
- alert("Ошибка в данных: " + e.message);
- } else {
- throw e; // неизвестная ошибка, не знаю что с ней делать
- }
-*/!*
-}
-```
-
-Обратим внимание -- в данном конкретном месте кода мы допускаем анонимных посетителей, поэтому в случае, если отсутствует `name` -- исправляем эту ошибку. Мы можем легко это сделать, благодаря наличию у `PropertyRequiredError` дополнительного (по сравнению со стандартными ошибками) свойства `property`.
-
-**Для проверки, какая именно ошибка произошла, вместо `e.name` используется `instanceof`.**
-
-Это позволяет как выделить какие-то отдельные типы ошибок (`e instanceof PropertyRequiredError`), так и проверить общий тип, с которым мы умеем работать, без оглядки на его детали (`e instanceof SyntaxError`).
-
-Благодаря `instanceof` мы получили удобную поддержку иерархии ошибок, с возможностью в любой момент добавить новые классы, понятным кодом и предсказуемым поведением.
-
## Итого
Оператор `obj instanceof Func` проверяет тот факт, что `obj` является результатом вызова `new Func`. Он учитывает цепочку `__proto__`, поэтому наследование поддерживается.
Оператор `instanceof` не сможет проверить тип значения, если объект создан в одном окне/фрейме, а проверяется в другом. Это потому, что в каждом окне -- своя иерархия объектов. Для точной проверки типов встроенных объектов можно использовать свойство `[[Class]]`.
-Оператор `instanceof` особенно востребован в случаях, когда мы работаем с иерархиями классов. Это наилучший способ проверить принадлежность тому или иному классу с учётом наследования.
+
+Оператор `instanceof` особенно востребован в случаях, когда мы работаем с иерархиями классов. Это наилучший способ проверить принадлежность тому или иному классу с учётом наследования.
diff --git a/1-js/9-prototypes/7-class-extend/article.md b/1-js/9-prototypes/7-class-extend/article.md
deleted file mode 100644
index 3483325e..00000000
--- a/1-js/9-prototypes/7-class-extend/article.md
+++ /dev/null
@@ -1,300 +0,0 @@
-# Фреймворк Class.extend
-
-Можно использовать прототипное наследование и не повторять `Rabbit.prototype.method = ...` при определении каждого метода, не иметь проблем с конструкторами и так далее.
-
-Для этого используют ООП-фреймворк -- библиотеку, в которой об этом подумали "за нас".
-
-В этой главе мы рассмотрим один из таких фреймворков:
-
-С удобным синтаксисом наследования.
-С вызовом родительских методов.
-С поддержкой статических методов и *примесей*.
-
-
-Можно сказать, что фреймворк представляет собой "синтаксический сахар" к наследованию на классах.
-[cut]
-
-Оригинальный код этого фреймворка были предложены Джоном Ресигом: [Simple JavaScript Inheritance](http://ejohn.org/blog/simple-javascript-inheritance/), но подход это не новый, его варианты используются во многих фреймворках и знакомство с ним будет очень кстати.
-
-Полный код фреймворка: [class-extend.js](http://js.cx/libs/class-extend.js). Он содержит много комментариев, чтобы было проще его понять, но смотреть его лучше после того, как ознакомитесь с возможностями.
-
-## Создание класса
-
-Итак, начнём.
-
-Фреймворк предоставляет всего один метод: `Class.extend`.
-
-Чтобы представлять себе, как выглядит класс "на фреймворке", взглянем на рабочий пример:
-
-```js
-//+ run
-// Объявление класса Animal
-var Animal = *!*Class.extend*/!*({
-
- init: function(name) {
- this.name = name;
- },
-
- run: function() {
- alert(this.name + " бежит!");
- }
-
-});
-
-// Создать (вызовется `init`)
-var animal = new Animal("Зверь");
-
-// Вызвать метод
-animal.run(); // "Зверь бежит!"
-```
-
-Готово, создан класс `Animal`.
-
-Внутри `Class.extend(props)` делает следующее:
-
-
-Создаётся объект, в который копируются свойства и методы из `prop`. Это будет прототип.
-Объявляется функция, которая вызывает `this.init`, в её `prototype` записывается созданный прототип.
-Эта функция возвращается, она и есть конструктор `Animal`.
-
-
-Как видим, всё весьма просто.
-
-Но фреймворк этим не ограничивается и добавляет ряд других интересных возможностей.
-
-## Статические свойства
-
-У метода `Class.extend` есть и второй, необязательный аргумент: объект `staticProps`.
-
-Если он есть, то его свойства копируются в саму функцию-конструктор.
-
-Например:
-
-```js
-//+ run
-// Объявить класс Animal
-var Animal = Class.extend({
-
- init: function(name){
- this.name = name;
- },
-
- toString: function(){
- return this.name;
- }
-
-},
-*!*
-{ // статические свойства
- compare: function(a, b) {
- return a.name - b.name;
- }
-});
-*/!*
-
-var arr = [new Animal('Зорька'), new Animal('Бурёнка')]
-
-*!*
-arr.sort(Animal.compare);
-*/!*
-
-alert(arr); // Бурёнка, Зорька
-```
-
-## Наследование
-
-Метод `extend` копируется в создаваемые классы.
-
-Поэтому его можно вызывать на любом конструкторе, чтобы создать ему класс-наследник.
-
-Например, создадим `Rabbit`, наследующий от `Animal`:
-
-```js
-//+ run
-// Создать Animal, всё как обычно
-var Animal = Class.extend({
- init: function(name) {
- this.name = name;
- },
- run: function() {
- alert(this.name + ' бежит!');
- }
-});
-
-// Объявить класс Rabbit, *!*наследующий*/!* от Animal
-var Rabbit = *!*Animal.extend*/!*({
-
- init: function(name) {
-*!*
- this._super(name); // вызвать родительский init(name)
-*/!*
- },
-
- run: function() {
- this._super(); // вызвать родительский run
- alert('..и мощно прыгает за морковкой!');
- }
-
-});
-
-*!*
-var rabbit = new Rabbit("Кроль");
-rabbit.run(); // "Кроль бежит!", затем "..и мощно прыгает за морковкой!"
-*/!*
-```
-
-## Метод this._super
-
-В коде выше появился ещё один замечательный метод: `this._super`.
-
-**Вызов `this._super(аргументы)` вызывает метод *родительского класса*, с указанными аргументами.**
-
-То есть, здесь он запустит родительский `init(name)`:
-
-```js
-init: function(name) {
- this._super(name); // вызвать родительский init(name)
-}
-```
-
-...А здесь -- родительский `run`:
-
-```js
-run: function() {
- this._super(); // вызвать родительский run
- alert('..и мощно прыгает за морковкой!');
-}
-```
-
-Работает это, примерно, так: когда фреймворк копирует методы в прототип, он смотрит их код, и если видит там слово `_super`, то оборачивает метод в обёртку, которая ставит `this._super` в метод родителя, затем вызывает метод, а затем возвращает `this._super` как было ранее.
-
-Это вызывает некоторые дополнительные расходы при объявлении, так как чтобы проверить, есть ли обращение к `_super`, фреймворк при копировании методов преобразует их через `toString` в строку и ищет в ней обращение.
-
-Как правило, эти расходы несущественны, если нужно их минимизировать -- не составляет труда изъять эту возможность из фреймворка или учесть в инструментах сжатия (минификации) кода.
-
-Кстати, примерно это минификатор Google Closure Compiler, когда сжимает код, написанный на "дружащей" с ним Google Closure Library.
-
-
-## Примеси [#mixins]
-
-Согласно теории ООП, *примесь* (англ. mixin) -- класс, реализующий какое-либо чётко выделенное поведение, который не предназначен для порождения самостоятельно используемых объектов, а используется для *уточнения* поведения других классов.
-
-Иными словами, *примесь* позволяет легко добавить в существующий класс новые возможности, например:
-
-Публикация событий и подписка на них.
-Работ c шаблонизатором.
-... любое поведение, дополняющее объект.
-
-
-**Как правило, примесь реализуется в виде объекта, свойства которого копируются в прототип.**
-
-Например, напишем примесь `EventMixin` для работы с событиями. Она будет содержать три метода -- `on/off` (подписка) и `trigger` (генерация события):
-
-```js
-var EventMixin = {
-
- on: function (eventName, handler) {
- if (!this._eventHandlers) this._eventHandlers = {};
- if (!this._eventHandlers[eventName]) {
- this._eventHandlers[eventName] = [];
- }
-
- this._eventHandlers[eventName].push(handler);
- },
-
- off: function(eventName, handler) {
- ...
- },
-
- trigger: function (eventName, args) {
- if (!this.eventHandlers || !this._eventHandlers[eventName]) {
- return;
- }
-
- var handlers = this._eventHandlers[eventName];
- for (var i = 0; i < handlers.length; i++) {
- handlers[i].apply(this, args);
- }
- }
-
-};
-```
-
-Скопировав свойства из `EventMixin` в любой объект, мы дадим ему возможность генерировать события (`trigger`) и подписываться на них (`on/off`).
-
-Чтобы было проще, во фреймворк добавлена возможность указания примесей при объявлении класса.
-
-**Для добавления примесей у метода `Class.extend` существует синтаксис с первым аргументом-массивом:**
-
-**`Class.extend([mixin1, mixin2...], props, staticProps)`.**
-
-
-Если первый аргумент -- массив, то его элементы `mixin1, mixin2..` записываются в прототип по очереди, перед `props`, примерно так:
-
-```js
-for(var key in mixin1) prototype[key] = mixin1[key];
-for(var key in mixin2) prototype[key] = mixin2[key];
-...
-for(var key in props) prototype[key] = props[key];
-```
-
-При этом, если названия методов совпадают, то последующий затрёт предыдущий, так как в объекте может быть только одно свойство с данным названием. Впрочем, обычно такого не происходит, т.к. примеси проектируются так, чтобы их методы были уникальными и ни с чем не конфликтовали.
-
-Применение:
-
-```js
-*!*
-var Rabbit = Class.extend( [ EventMixin ], {
-*/!*
-
- /* свойства и методы для Rabbit */
-
-});
-
-var rabbit = new Rabbit();
-
-*!*rabbit.on*/!*("jump", function() { // повесить функцию на событие jump
- alert("jump &-@!");
-});
-
-*!*rabbit.trigger*/!*('jump'); // alert сработает!
-```
-
-Примеси могут быть самыми разными. Например `TemplateMixin` для работы с шаблонами:
-
-```js
-Rabbit = Class.extend([EventMixin, TemplateMixin], {
-
- /* Теперь Rabbit умеет использовать события и шаблоны */
-
-});
-```
-
-Красиво, не правда ли? Всего лишь указали одну-другую примесь и объект уже всё умеет!
-
-Примеси могут задавать и многое другое, например автоматически подписывать компонент на стандартные события, добавлять AJAX-функционал и т.п.
-
-## Итого
-
-
-**Фреймворк имеет основной метод `Class.extend` с несколькими вариациями:**
-
-`Class.extend(props)` -- просто класс с прототипом `props`.
-`Class.extend(props, staticProps)` -- класс с прототипом `props` и статическими свойствами `staticProps`.
-`Class.extend(mixins, props [, staticProps])` -- если первый аргумент массив, то он интерпретируется как примеси. Их свойства копируются в прототип перед `props`.
-
-
-**У созданных этим методом классов также есть `extend` для продолжения наследования.**
-**Методы родителя можно вызвать при помощи `this._super(...)`.**
-
-
-Плюсы и минусы:
-[compare]
-+Такой фреймворк удобен потому, что класс можно задать одним вызовом `Class.extend`, с читаемым синтаксисом, удобным наследованием и вызовом родительских методов.
--Редакторы и IDE, как правило, не понимают такой синтаксис, а значит, не предоставляют автодополнение. При этом они обычно понимают объявление методов через явную запись в объект или в прототип.
--Есть некоторые дополнительные расходы, связанные с реализацией `_super`. Если они критичны, то их можно избежать.[/compare]
-
-То, как работает фреймворк, подробно описано в комментариях: [class-extend.js](http://js.cx/libs/class-extend.js).
-[head]
-
-[/head]
\ No newline at end of file
diff --git a/1-js/9-prototypes/7-oop-errors/1-format-error/solution.md b/1-js/9-prototypes/7-oop-errors/1-format-error/solution.md
new file mode 100644
index 00000000..75e08b3e
--- /dev/null
+++ b/1-js/9-prototypes/7-oop-errors/1-format-error/solution.md
@@ -0,0 +1,28 @@
+```js
+//+ run
+function FormatError(message) {
+ this.name = "FormatError";
+
+ this.message = message;
+
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this, this.constructor);
+ } else {
+ this.stack = (new Error()).stack;
+ }
+
+}
+
+FormatError.prototype = Object.create(SyntaxError.prototype);
+FormatError.prototype.constructor = FormatError;
+
+// Использование
+
+var err = new FormatError("ошибка форматирования");
+
+alert(err.message); // ошибка форматирования
+alert(err.name); // FormatError
+alert(err.stack); // стек на момент генерации ошибки
+
+alert(err instanceof SyntaxError); // true
+```
\ No newline at end of file
diff --git a/1-js/9-prototypes/7-oop-errors/1-format-error/task.md b/1-js/9-prototypes/7-oop-errors/1-format-error/task.md
new file mode 100644
index 00000000..26201691
--- /dev/null
+++ b/1-js/9-prototypes/7-oop-errors/1-format-error/task.md
@@ -0,0 +1,17 @@
+# Унаследуйте от SyntaxError
+
+[importance 5]
+
+Создайте ошибку `FormatError`, которая будет наследовать от встроенного класса `SyntaxError`.
+
+Синтаксис для её создания -- такой же, как обычно:
+
+```js
+var err = new FormatError("ошибка форматирования");
+
+alert(err.message); // ошибка форматирования
+alert(err.name); // FormatError
+alert(err.stack); // стек на момент генерации ошибки
+
+alert(err instanceof SyntaxError); // true
+```
diff --git a/1-js/9-prototypes/7-oop-errors/article.md b/1-js/9-prototypes/7-oop-errors/article.md
new file mode 100644
index 00000000..e736fc44
--- /dev/null
+++ b/1-js/9-prototypes/7-oop-errors/article.md
@@ -0,0 +1,230 @@
+# Свои ошибки, наследование от Error
+
+Когда мы работаем с внешними данными, возможны самые разные ошибки.
+
+Если приложение сложное, то ошибки естественным образом укладываются в иерархию, разобраться в которой помогает `instanceof`.
+
+## Свой объект ошибки
+
+Для примера создадим функцию `readUser(json)`, которая будет разбирать JSON с данными посетителя. Мы его получаем с сервера -- может, нашего, а может -- чужого, в общем -- желательно проверить на ошибки. А может, это даже и не JSON, а какие-то другие данные -- не важно, для наглядности поработаем с JSON.
+
+Пример `json` на входе в функцию: `{ "name": "Вася", "age": 30 }`.
+
+В процессе работы `readUser` возможны различные ошибки. Одна -- очевидно, `SyntaxError` -- если передан некорректный JSON.
+
+Но могут быть и другие, например `PropertyError` -- эта ошибка будет возникать, если в прочитанном объекте нет свойства `name` или `age`.
+
+Реализуем её:
+
+```js
+function PropertyError(property) {
+ this.name = "PropertyError";
+
+ this.property = property;
+ this.message = "Ошибка в свойстве " + property;
+
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this, PropertyError);
+ } else {
+ this.stack = (new Error()).stack;
+ }
+
+}
+
+PropertyError.prototype = Object.create(Error.prototype);
+```
+
+Посмотрим внимательнее на код -- в нём важные детали того, как можно позаботиться о стандартных свойствах объекта ошибки:
+
+
+`name` -- имя ошибки.
+Должно совпадать с именем функции, просто записали строку в него.
+`message` -- сообщение об ошибке.
+Несмотря на то, что `PropertyError` наследует от `Error` (последняя строка), конструктор у неё немного другой. Он принимает не сообщение об ошибке, а название свойства `property`, ну а сообщение генерируется из него.
+
+В результате в ошибке есть как стандартное свойство `message`, так и более точное `property`.
+
+Это полезная практика -- добавлять в объект ошибки свойства, более подробно описывающие ситуацию, которых нет в базовых объектах `Error`.
+`stack` -- стек вызовов, которые в итоге привели к ошибке.
+У встроенных объектов `Error` это свойство есть автоматически, вот к примеру:
+```js
+//+ run
+function f() {
+ alert( new Error().stack );
+}
+
+f();
+```
+
+Если же объект делаем мы, то "по умолчанию" такого свойства у него не будет. Нам нужно как-то самим узнавать последовательность вложенных вызовов на текущий момент. Однако удобного способа сделать это в JavaScript нет, поэтому мы поступаем хитро и копируем его из нового объекта `new Error`, который генерируем тут же.
+
+В V8 (Chrome, Opera, Node.JS) есть нестандартное расширение [Error.captureStackTrace](https://code.google.com/p/v8-wiki/wiki/JavaScriptStackTraceApi), которое позволяет стек получать.
+
+Строка из кода выше:
+```js
+Error.captureStackTrace(this, PropertyError);
+```
+
+Вызов записывает в объект `this` (текущий объект ошибки) стек вызовов, а второй аргумент -- это текущий конструктор, он не обязателен, но если есть, то говорит, что при генерации стека нужно на этой функции остановиться. В результате в стеке не будет информации о том, что делалось внутри конструктора `PropertyError`.
+
+То есть, будет последовательность вызовов до генерации ошибки, но не включая код самого конструктора ошибки, который, как правило, не интересен. Такое поведение максимально соответствует встроенным ошибкам JavaScript.
+
+
+
+[smart header="Конструктор родителя здесь не нужен"]
+В коде выше не вызывается конструктор родителя. Обычно, когда мы наследуем, то мы вызываем его.
+
+В данном случае вызов выглядел бы как `Error.call(this, message)`.
+
+Однако, встроенный конструктор `Error` на редкость прост, он ничего полезного не делает, даже свойство `this.message` (не говоря уже об `name` и `stack`) не назначает. Поэтому и вызывать его здесь нет необходимости.
+[/smart]
+
+
+## instanceof + try..catch = ♡
+
+Давайте теперь используем наш новый класс для `readUser`:
+
+```js
+//+ run
+*!*
+// Объявление
+*/!*
+function PropertyError(property) {
+ this.name = "PropertyError";
+
+ this.property = property;
+ this.message = "Отсутствует свойство " + property;
+
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this, PropertyError);
+ } else {
+ this.stack = (new Error()).stack;
+ }
+
+}
+
+PropertyError.prototype = Object.create(Error.prototype);
+
+*!*
+// Генерация ошибки
+*/!*
+function readUser(data) {
+
+ var user = JSON.parse(data);
+
+ if (!user.age) {
+ throw new PropertyError("age");
+ }
+
+ if (!user.name) {
+ throw new PropertyError("name");
+ }
+
+ return user;
+}
+
+*!*
+// Запуск и try..catch
+*/!*
+
+try {
+ var user = readUser('{ "age": 25 }');
+} catch (err) {
+ if (err instanceof PropertyError) {
+ if (err.property == 'name') {
+ // если в данном месте кода возможны анонимы, то всё нормально
+*!*
+ alert("Здравствуйте, Аноним!");
+*/!*
+ } else {
+ alert(err.message); // Отсутствует свойство ...
+ }
+ } else if (err instanceof SyntaxError) {
+ alert("Ошибка в данных: " + err.message);
+ } else {
+ throw err; // неизвестная ошибка, не знаю что с ней делать
+ }
+}
+```
+
+Обратим внимание на проверку типа ошибки в `try..catch`.
+
+Оператор `instanceof` поддерживает иерархию. Это значит, что если мы в дальнейшем решим как-то ещё уточнить тип ошибки `PropertyError`, то для объекта, наследующего от него, `e instanceof PropertyError` по-прежнему будет работать.
+
+## Дальнейшее наследование
+
+Чтобы создать иерархию, нужно наследовать от `PropertyError`.
+
+`PropertyError` -- это просто общего вида ошибка в свойстве. Создадим ошибку `PropertyRequiredError`, которая означает, что свойства нет.
+
+Типичный вид конструктора-наследника -- такой:
+
+```js
+function PropertyRequiredError(property) {
+ PropertyError.apply(this, arguments);
+ ...
+}
+```
+
+Можем ли мы просто вызвать конструктор родителя и ничего не делать в дополнение? Увы, нет.
+
+Если так поступить, то свойство `this.name` будет некорректным, да и `Error.captureStackTrace` тоже получит неправильную функцию вторым параметром.
+
+Можно ли как-то поправить конструктор родителя? Убрать из него все упоминания о конкретном классе `PropertyError` и сделать код универсальным?
+
+Частично -- да. Как мы помним, существует свойство `constructor`, которое есть в `prototype` по умолчанию, и которое мы можем намеренно сохранить при наследовании:
+
+```js
+function PropertyError(property) {
+ this.name = "PropertyError";
+
+ this.property = property;
+ this.message = "Отсутствует свойство " + property;
+
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this, *!*this.constructor*/!*); // (*)
+ } else {
+ this.stack = (new Error()).stack;
+ }
+
+}
+
+PropertyError.prototype = Object.create(Error.prototype);
+*!*
+PropertyError.prototype.constructor = PropertyError;
+*/!*
+```
+
+В строке `(*)` это свойство было использовано, чтобы получить конструктор уже не в виде жёсткой ссылки `PropertyError`, а тот, который использован для текущего объекта. В наследнике там будет `PropertyRequiredError`, как и задумано.
+
+Мы убрали одно упоминание, но с `this.name`, увы, сложности. Сейчас при наследовании оно будет всегда `"PropertyError"`. Все браузеры, кроме IE11-, поддерживают имя у Function Declaration, то есть имя функции можно было бы получить из `this.constructor.name`, но в IE11- это работать не будет.
+
+Если подерживать IE11-, то тут уж придётся в наследнике его записывать вручную.
+
+Полный код для наследника:
+
+```js
+function PropertyRequiredError(property) {
+ PropertyError.apply(this, arguments);
+ this.name = 'PropertyRequiredError';
+ this.message = 'Отсутствует свойство ' + property;
+}
+
+PropertyRequiredError.prototype = Object.create(PropertyError);
+PropertyRequiredError.prototype.constructor = PropertyRequiredError;
+
+var err = new PropertyRequiredError("age");
+// пройдёт проверку
+alert(err instanceof PropertyError); // true
+```
+
+Здесь заодно и `message` было перезаписано на более точное. Если хочется избежать записи и перезаписи, то можно оформить его в виде геттера через `Object.defineProperty`.
+
+## Итого
+
+
+Чтобы наследовать встроенному классу ошибок `Error`, нужно самостоятельно позаботиться о `name`, `message` и `stack`.
+Благодаря `instanceof` мы получили удобную поддержку иерархии ошибок, с возможностью в любой момент добавить новые классы, понятным кодом и предсказуемым поведением.
+
+
+Чтобы создавать наследники от `Error` было проще, можно создать класс `CustomError`, записать в него универсальный код, наподобие `PropertyError` и далее наследовать уже от него.
diff --git a/1-js/9-prototypes/8-why-prototypes-better/article.md b/1-js/9-prototypes/8-why-prototypes-better/article.md
deleted file mode 100644
index 1bb6e93a..00000000
--- a/1-js/9-prototypes/8-why-prototypes-better/article.md
+++ /dev/null
@@ -1,266 +0,0 @@
-# Сравнение с функциональным наследованием
-
-В этой главе мы озаботимся тем, чтобы сравнить прототипный и функциональный подход к ООП.
-
-Причём, сделать это грамотно, с учётом того, что реально происходит "под капотом" интерпретатора.
-
-Нас интересуют три показателя:
-
-Эффективность по памяти.
-Скорость работы.
-Архитектурные ограничения (если есть) и плюшки.
-
-
-[cut]
-
-## Класс Machine
-
-Объявим класс `Machine` двумя способами:
-
-Функциональное объявление:
-Состоит из единственной функции-конструктора, которая записывает в объект всё, что нужно. Приватные данные сохраняются в локальные переменные и доступны через замыкание:
-
-```js
-function MachineOne(power) {
- var enabled = false;
-
- this.enable = function() { enabled = true; };
- this.disable = function() { enabled = false; };
-
- // ...
-}
-```
-
-При этом у каждого объекта будет своя копия методов `enable` и `disable`, которые создаются каждый раз заново.
-
-Прототипное объявление:
-В объекте хранится только то, что ему нужно. Методы записываются в прототип:
-
-```js
-function MachineTwo(power) {
- this._enabled = false;
-}
-
-MachineTwo.prototype.enable = function() {
- this._enabled = true;
-};
-
-MachineTwo.prototype.disable = function() {
- this._enabled = false;
-};
-```
-
-
-
-
-## Сравнение памяти
-
-Оценим затраты памяти в функциональном стиле:
-
-```js
-var machine = new MachineOne();
-
-затраты памяти =
- сам объект +
- свойства и методы в нём (this.enable/disable) +
- замыкание, объект с приватными переменными (var enabled)
-```
-
-В этой, казалось бы, очевидной формуле кроется серьёзная ошибка.
-
-По коду кажется, каждый объект хранит свою копию методов `this.enable/disable`, однако это не совсем так.
-
-Интерпретаторы оптимизируют создание и хранение одинаковых одинаковых функций. "Под капотом" *строка с кодом* функции `enable/disable` хранится только один раз, и её разделяют между собой все объекты `MachineOne`. То есть, если вывести функцию в виде строки `alert(machine.enable)`, то каждый объект возьмёт код из единого для всех места в памяти.
-
-Далее, при использовании, строка с кодом на JavaScript превращается в *машинный код*, который может по-разному оптимизироваться, в зависимости от того, как именно используется функция, но и здесь интерпретатор старается разделять одинаково оптимизированный код между объектами.
-
-**То есть, на самом деле в каждом объекте хранится не полная копия метода, а скорее "метаданные", которые указывают, где в памяти лежит соответствующим образом оптимизированная функция.**
-
-Теперь прототипный стиль:
-
-```js
-var machine = new MachineTwo();
-
-затраты памяти =
- сам объект +
- свойства (this._enabled)
-```
-
-Если сравнить, то мы видим, что значение `var enabled` переместилось в сам объект, произошла небольшая экономия на объекте LexicalEnvironment, который больше не нужен.
-
-Кроме того, методы находятся в прототипе. Интерпретатор делает неплохую работу по оптимизации функционального стиля можно сказать, что "почти вся" информация о функциях будет разделяться между объектами, но в прототипном подходе функции разделяются на 100%, без "почти".
-
-**Вывод: прототипный стиль требует меньше памяти, так как не хранится LexicalEnvironment и методы (совсем).**
-
-В случае, когда объект хранит мало данных, и методы маленькие, разница в памяти может быть существенной. В браузере Chrome (V8) для описанных выше `MachineOne` и `MachineTwo` она может составлять 5-8 раз. Но это лишь потому, что объекты полностью синтетические, в них почти нет кода и данных. В реальности она меньше, порядка 1-3 раз, конечно это зависит от конкретного объекта.
-
-## Сравнение производительности
-
-Создание объекта в функциональном стиле дольше, поскольку происходят присвоения в `this`. Это очевидно.
-
-Но может показаться, что при этом скорость доступа к таким методом "особо быстрая", так как они хранятся в самом объекте, а не в его прототипе.
-
-Это не так.
-
-"Под капотом" интерпретатор при первом вызове метода пробежится по цепочке `__proto__`, запомнит место, где его нашёл, и далее будет обращаться прямо туда.
-
-**В современных браузерах скорость доступа к методам в прототипе и в объекте одинакова.**
-
-Функциональный стиль и здесь не имеет преимущества.
-
-## Красота синтаксиса
-
-В функциональном стиле мы имеем красивые приватные переменные и функции. Это хорошо.
-
-Но пользоваться публичными методами менее удобно.
-
-Скажем, мы хотим при создании `new Machine` тут же включить машину вызовом `this.enable()`:
-
-```js
-function Machine(power) {
- var enabled = false;
-
- this.enable = function() { enabled = true; };
- this.disable = function() { enabled = false; };
-
-*!*
- // нужно писать этот вызов внизу
- this.enable();
-*/!*
-}
-```
-
-Мы вынуждены написать вызов `this.enable()` внизу, под определением соответствующего метода.
-
-**Если методов много и они длинные, то получается, что при чтении кода нам нужно проматывать в конец файла. Это неудобно!**
-
-Типичное средство обхода -- объявлять все методы через Function Declaration, а внизу выносить во внешний интерфейс нужные:
-
-```js
-function Machine(power) {
- var enabled = false;
-
- enable();
-
- function enable() { enabled = true; };
- function disable() { enabled = false; };
-
-*!*
- this.enable = enable;
- this.disable = disable;
-*/!*
-}
-```
-
-Ничего такого, но приходится писать лишние буквы, а у программиста и так нелёгкий труд.
-
-Прототипное наследование похожей проблемы не имеет. Зато там нужно писать слово `prototype`, что, впрочем, исправляется различными ООП-фреймворками.
-
-## Архитектурные ограничения
-
-Наследование, реализованное в функциональном стиле, обладает важным архитектурным ограничением.
-
-**Конструктор наследника получает контроль лишь после полной инициализации родителя, и это может быть слишком поздно.**
-
-Например, пусть конструктор `Machine` при инициализации вызывает свой метод `work()`. Это достаточно типично, что при создании объект тут же делает что-то полезное или заполняет себя важными данными.
-
-Потомок -- `CoffeeMachine` захочет переопределить этот метод. Реализация будет выглядеть так:
-
-```js
-//+ run
-// Родитель:
-
-function Machine() {
- this.work = function() {
- alert('Гр-р-р-р! Бям-бямс...');
- };
-
- this.work();
-}
-
-// Потомок:
-
-function CoffeeMachine() {
- Machine.apply(this, arguments);
-
-*!*
- // попытаемся переопределить метод в потомке
- this.work = function() {
- alert('Вжжжжжжжжж!');
- };
-*/!*
-}
-
-// переопределение не сработало!
-*!*
-var coffeeMachine = new CoffeeMachine(); // Гр-р-р-р! Бям-бямс...!
-*/!*
-```
-
-Вызвался метод `work` не потомка, а родителя!
-
-Это естественно, ведь первым делом мы вызвали `Machine.apply(this, arguments)`, в котором используется старый `work`.
-
-**Методы для инициализации, уже использованные родителем, переопределить в потомке нельзя: слишком поздно.**
-
-Недостаток этот -- весьма серьёзный. Фактически, он ограничивает возможности построения архитектуры.
-
-Заметим, что при использовании прототипов такой проблемы не возникает. Потому что сначала полностью задаются конструкторы, методы, задаётся порядок поиска через прототипы, а уже *потом* создаются объекты.
-
-Аналогичный код через прототипы:
-
-```js
-//+ run
-function Machine() {
- this.work();
-}
-Machine.prototype.work = function() {
- alert('Гр-р-р-р! Бям-бямс...');
-};
-
-function CoffeeMachine() {
- Machine.apply(this, arguments);
-}
-CoffeeMachine.prototype = Object.create(Machine.prototype);
-
-CoffeeMachine.prototype.work = function() {
- alert('Вжжжжжжжжж!');
-};
-
-// переопределение сработает, work найден в CoffeeMachine.prototype
-*!*
-var coffeeMachine = new CoffeeMachine(); // Вжжжжжжжжж!
-*/!*
-```
-
-## Не учитывается наследование в instanceof
-
-Есть и ещё одна проблема функционального подхода.
-
-При наследовании в функциональном стиле проверка `coffeeMachine instanceof Machine` вернёт `false`.
-
-Это вполне естественно, ведь, формально говоря, `CoffeeMachine` не является `Machine`.
-
-Единственная связь между ними -- конструктор `CoffeeMachine` вызвал функцию `Machine` в своём контексте. Оператор `instanceof` работает через проверку цепочки прототипов, а здесь её нет.
-
-**Здесь прототипный подход гораздо удобнее.**
-
-Конечно, можно попробовать запоминать, кого и в каком порядке вызывали, разработать свой аналог `instanceof`, но обычно так не делают, т.к. в прототипах встроенный `instanceof` просто работает.
-
-## Сжатие JavaScript
-
-При функциональном наследовании используются локальные переменные и функции.
-
-Современные средства сжатия JavaScript переименовывают их, делая короче и таким образом уменьшая размер кода.
-
-**Это означает, что код, написанный в функциональном стиле, сожмётся лучше.**
-
-## Итого
-
-Получилось, что функциональный паттерн в сочетании с наследованием обладает рядом серьёзных проблем.
-
-Его, по сути, основное достоинство -- это использование локальных функций и переменных, в которые никак нельзя залезть снаружи, и которые дают лучшее сжатие кода минификаторами.
-
-Кроме того, если программировать без фреймворков, то функциональный стиль -- наиболее нагляден и прост.
-
-Но если в проекте нужен единообразный стиль ООП, то лучше использовать прототипный подход, возможно прибавив "сахарку" в виде ООП-фреймворка (тысячи их), а функциональный использовать в тех случаях, когда *уже есть* сторонняя библиотека или конструкторы в этом стиле, которые нужно расширить.
diff --git a/2-ui/1-document/10-compare-document-position/article.md b/2-ui/1-document/10-compare-document-position/article.md
index e52dbd5a..22f23a06 100644
--- a/2-ui/1-document/10-compare-document-position/article.md
+++ b/2-ui/1-document/10-compare-document-position/article.md
@@ -194,7 +194,7 @@ function compareDocumentPosition(a, b) {
```
Список битовых масок для проверки:
-
+
Биты
Число
diff --git a/2-ui/1-document/7-attributes-and-custom-properties/article.md b/2-ui/1-document/7-attributes-and-custom-properties/article.md
index 85747058..c4be92c5 100644
--- a/2-ui/1-document/7-attributes-and-custom-properties/article.md
+++ b/2-ui/1-document/7-attributes-and-custom-properties/article.md
@@ -422,7 +422,7 @@ alert( document.body.getAttribute('AbBa') ); // что должен вернут
Таблица сравнений для атрибутов и свойств:
-
+
Свойства
Атрибуты
diff --git a/2-ui/3-event-details/8-keyboard-events/article.md b/2-ui/3-event-details/8-keyboard-events/article.md
index 9802e62d..03b290bd 100644
--- a/2-ui/3-event-details/8-keyboard-events/article.md
+++ b/2-ui/3-event-details/8-keyboard-events/article.md
@@ -229,7 +229,7 @@ document.getElementById('my').onkeypress = function(e) {
Перечислим их в таблице, обращая основное внимание на особенности работы с ними.
-
+
Категория
Примеры
diff --git a/2-ui/4-forms-controls/3-events-change/article.md b/2-ui/4-forms-controls/3-events-change/article.md
index bc671cb4..7b181559 100644
--- a/2-ui/4-forms-controls/3-events-change/article.md
+++ b/2-ui/4-forms-controls/3-events-change/article.md
@@ -175,7 +175,7 @@ function showCount() {
События изменения данных:
-
+
Событие
Описание
diff --git a/3-more/1-webcomponents/2-webcomponent-core/article.md b/3-more/1-webcomponents/2-webcomponent-core/article.md
index 1c1bd54f..426b444a 100644
--- a/3-more/1-webcomponents/2-webcomponent-core/article.md
+++ b/3-more/1-webcomponents/2-webcomponent-core/article.md
@@ -169,7 +169,7 @@ var timer = document.createElement("button", "my-timer");
Следующие методы автоматически вызываются во время жизненного цикла элемента:
-
+
`createdCallback` Элемент создан
`attachedCallback` Элемент добавлен в документ
`detachedCallback` Элемент удалён из документа
diff --git a/3-more/10-ajax/16-ajax-summary/article.md b/3-more/10-ajax/16-ajax-summary/article.md
index d1cade8b..f3415c10 100644
--- a/3-more/10-ajax/16-ajax-summary/article.md
+++ b/3-more/10-ajax/16-ajax-summary/article.md
@@ -25,7 +25,7 @@
Они были детально рассмотрены в предыдущих главах раздела.
-
+
`XMLHttpRequest`
diff --git a/3-more/2-animation/2-bezier/article.md b/3-more/2-animation/2-bezier/article.md
index 6e7497fb..9696fd1b 100644
--- a/3-more/2-animation/2-bezier/article.md
+++ b/3-more/2-animation/2-bezier/article.md
@@ -112,7 +112,7 @@ if (!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Basi
На каждом из этих отрезков берётся точка, находящаяся от начала на расстоянии от 0 до `t` пропорционально длине. То есть, при `t=0` -- точка будет в начале, при `t=0.25` -- на расстоянии в 25% от начала отрезка, при `t=0.5` -- 50%(на середине), при `t=1` -- в конце. Так как **чёрных** отрезков -- два, то и точек выходит две штуки.
Эти точки соединяются. На рисунке ниже соединяющий их отрезок изображён синим .
-
+
При `t=0.25` При `t=0.5`
diff --git a/3-more/2-animation/3-css-animation/article.md b/3-more/2-animation/3-css-animation/article.md
index 2dd69883..91b041f0 100644
--- a/3-more/2-animation/3-css-animation/article.md
+++ b/3-more/2-animation/3-css-animation/article.md
@@ -166,7 +166,7 @@ CSS-анимации особенно рекомендуются на мобил
Остальные кривые являются короткой записью следующих `cubic-bezier`. В таблице ниже показано соответствие:
-
+
`ease`
`ease-in`
diff --git a/3-more/5-compress/3-gcc-advanced-optimization/article.md b/3-more/5-compress/3-gcc-advanced-optimization/article.md
index 8e7bf6ca..fbcdb00c 100644
--- a/3-more/5-compress/3-gcc-advanced-optimization/article.md
+++ b/3-more/5-compress/3-gcc-advanced-optimization/article.md
@@ -370,10 +370,10 @@ SayWidget.prototype['setSayHandler'] = SayWidget.prototype.setSayHandler
Но, в остальном, это совершенно разные вещи.
-
+
-Экстерн
-Экспорт
+Экстерн
+Экспорт
diff --git a/3-more/6-extra/11-intl/article.md b/3-more/6-extra/11-intl/article.md
index 4e739b7f..3b4cb175 100644
--- a/3-more/6-extra/11-intl/article.md
+++ b/3-more/6-extra/11-intl/article.md
@@ -147,7 +147,7 @@ var formatter = new Intl.DateFormatter([locales, [options] ])
Первый аргумент -- такой же, как и в `Collator`, а в объекте `options` мы можем определить, какие именно части даты показывать (часы, месяц, год...) и в каком формате.
Полный список свойств `options`:
-
+
Свойство
Описание
@@ -321,7 +321,7 @@ formatter.format(number); // форматирование
Список опций:
-