Первый `alert` здесь работает очевидным образом -- он выводит свойство `jumps` объекта `rabbit`.
@@ -37,18 +34,7 @@ alert(rabbit.eats); // true
Иллюстрация происходящего при чтении `rabbit.eats` (поиск идет снизу вверх):
-```js
-var animal = {
- eats: true
-};
-
-var rabbit = {
- jumps: true
-};
-```
-
-
-
+
**Объект, на который указывает ссылка `__proto__`, называется *"прототипом"*. В данном случае получилось, что `animal` является прототипом для `rabbit`.**
@@ -72,38 +58,16 @@ alert(rabbit.eats); // false, свойство взято из rabbit
**Другими словами, прототип -- это "резервное хранилище свойств и методов" объекта, автоматически используемое при поиске.**
+У объекта, который является `__proto__`, может быть свой `__proto__`, у того -- свой, и так далее. При этом свойства будут искаться по цепочке.
+
[smart header="Ссылка __proto__ в спецификации"]
Если вы будете читать спецификацию EcmaScript -- свойство `__proto__` обозначено в ней как `[[Prototype]]`.
Двойные квадратные скобки здесь важны, чтобы не перепутать его с совсем другим свойством, которое называется `prototype`, и которое мы рассмотрим позже.
[/smart]
-
-## Цепочка прототипов
-
-У объекта, который является `__proto__`, может быть свой `__proto__`, у того -- свой, и так далее.
-
-Например, цепочка наследования из трех объектов `donkey -> winnie -> owl`:
-
-```js
-//+ run
-var donkey = { /* ... */ };
-var winnie = { /* ... */ };
-var owl = { knowsAll: true };
-
-donkey.__proto__ = winnie;
-winnie.__proto__ = owl;
-
-*!*
-alert( donkey.knowsAll ); // true
-*/!*
-```
-
-Картина происходящего:
-
-
-## Перебор свойств без прототипа
+## Метод hasOwnProperty
Обычный цикл `for..in` не делает различия между свойствами объекта и его прототипа.
@@ -172,28 +136,28 @@ for (var key in rabbit) {
}
```
+
## Методы для работы с __proto__
В современных браузерах есть два дополнительных метода для работы с `__proto__`. Зачем они нужны, если есть `__proto__`? В общем-то, не очень нужны, но по историческим причинам тоже существуют.
Создаёт пустой объект с `__proto__`, равным первому аргументу (кроме IE8-).
+
Создание объекта с прототипом: [Object.create(proto, descriptors)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create)
+
Создаёт пустой объект с `__proto__`, равным первому аргументу (кроме IE8-), второй необязательный аргумент может содержать [дескрипторы свойств](/descriptors-getters-setters).
-Метод `Object.create` -- несколько более мощный, чем здесь описано, у него есть необязательный второй аргумент, который позволяет также задать другие свойства объекта, но используется он редко и пока что нам не нужен. Мы рассмотрим его позже, в главе [](/descriptors-getters-setters).
-
## Итого
+
-
Объекты в JavaScript можно организовать в цепочку при помощи специального свойства `__proto__`.
+
В JavaScript есть встроенное "наследование" между объектами при помощи специального свойства `__proto__`.
При установке свойства `rabbit.__proto__ = animal` говорят, что объект `animal` будет "прототипом" `rabbit`.
При чтении свойства из объекта, если его в нём нет, оно ищется в `__proto__`. Прототип задействуется только при чтении свойства. Операции присвоения `obj.prop =` или удаления `delete obj.prop` совершаются всегда над самим объектом `obj`.
@@ -205,12 +169,12 @@ for (var key in rabbit) {
[Object.getPrototypeOf(obj)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/getPrototypeOf) (кроме IE8-)
[Object.setPrototypeOf(obj, proto)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/setPrototypeOf) (кроме IE10-)
-
[Object.create(proto)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create) (кроме IE8-)
+
[Object.create(proto, descriptors)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create) (кроме IE8-)
-Возможно, вас смущает недостаточная поддержка `__proto__` в старых IE. Но это временно. В последующих главах мы рассмотрим дополнительные методы работы с `__proto__`, включая те, которые работают везде.
+Возможно, вас смущает недостаточная поддержка `__proto__` в старых IE. Но это не страшно. В последующих главах мы рассмотрим дополнительные методы работы с `__proto__`, включая те, которые работают везде.
-Также мы рассмотрим, как свойство `__proto__` используется внутри самого языка JavaScript.
+Также мы рассмотрим, как свойство `__proto__` используется внутри самого языка JavaScript и как организовать классы с его помощью.
diff --git a/1-js/9-prototypes/1-prototype/donkey_winnie_owl.png b/1-js/9-prototypes/1-prototype/donkey_winnie_owl.png
deleted file mode 100755
index 82352906..00000000
Binary files a/1-js/9-prototypes/1-prototype/donkey_winnie_owl.png and /dev/null differ
diff --git a/1-js/9-prototypes/1-prototype/donkey_winnie_owl@2x.png b/1-js/9-prototypes/1-prototype/donkey_winnie_owl@2x.png
deleted file mode 100755
index 3a3d1ca3..00000000
Binary files a/1-js/9-prototypes/1-prototype/donkey_winnie_owl@2x.png and /dev/null differ
diff --git a/1-js/9-prototypes/1-prototype/proto-animal-rabbit.svg b/1-js/9-prototypes/1-prototype/proto-animal-rabbit.svg
index 719fbf26..a3bfc80b 100644
--- a/1-js/9-prototypes/1-prototype/proto-animal-rabbit.svg
+++ b/1-js/9-prototypes/1-prototype/proto-animal-rabbit.svg
@@ -1,22 +1,34 @@
-
-
-Эта функция широко используется в библиотеках и фреймворках.
-
-Здесь и далее мы будем использовать `Object.create`, предполагая что для IE8- выполнен код:
+Для унификации можно запустить такой код, и метод `Object.create` станет кросс-браузерным:
```js
if (!Object.create) Object.create = inherit; /* определение inherit - выше */
@@ -135,12 +198,15 @@ if (!Object.create) Object.create = inherit; /* определение inherit -
В частности, аналогичным образом работает библиотека [es5-shim](https://github.com/es-shims/es5-shim), при подключении которой `Object.create` станет доступен для всех браузеров.
+
## Итого
+Для произвольной функции -- назовём её `Constructor`, верно следующее:
+
-
Прототип новых объектов, создаваемых через `new`, можно задавать кросс-браузерно, при помощи свойства конструктора `prototype`.
-
При создании объекта через `new F`, в его `__proto__` записывается ссылка на объект `F.prototype`.
-
Современный метод `Object.create(proto)` можно эмулировать его при помощи `prototype`, если хочется, чтобы он работал в IE8-.
+
Прототип `__proto__` новых объектов, создаваемых через `new Constructor`, можно задавать при помощи свойства `Constructor.prototype`.
+
Значением `Constructor.prototype` по умолчанию является объект с единственным свойством `constructor`, содержащим ссылку на `Constructor`. Его можно использовать, чтобы из самого объекта получить функцию, которая его создала. Однако, JavaScript никак не поддерживает корректность этого свойства, поэтому программист может его изменить или удалить.
+
Современный метод `Object.create(proto)` можно эмулировать при помощи `prototype`, если хочется, чтобы он работал в IE8-.
diff --git a/1-js/9-prototypes/3-native-prototypes/5.png b/1-js/9-prototypes/3-native-prototypes/5.png
deleted file mode 100755
index f4202de0..00000000
Binary files a/1-js/9-prototypes/3-native-prototypes/5.png and /dev/null differ
diff --git a/1-js/9-prototypes/3-native-prototypes/5@2x.png b/1-js/9-prototypes/3-native-prototypes/5@2x.png
deleted file mode 100755
index 9adfa463..00000000
Binary files a/1-js/9-prototypes/3-native-prototypes/5@2x.png and /dev/null differ
diff --git a/1-js/9-prototypes/3-native-prototypes/6.png b/1-js/9-prototypes/3-native-prototypes/6.png
deleted file mode 100755
index a4ab88fd..00000000
Binary files a/1-js/9-prototypes/3-native-prototypes/6.png and /dev/null differ
diff --git a/1-js/9-prototypes/3-native-prototypes/6@2x.png b/1-js/9-prototypes/3-native-prototypes/6@2x.png
deleted file mode 100755
index 6ac1ba26..00000000
Binary files a/1-js/9-prototypes/3-native-prototypes/6@2x.png and /dev/null differ
diff --git a/1-js/9-prototypes/3-native-prototypes/article.md b/1-js/9-prototypes/3-native-prototypes/article.md
index 590286ec..086c4219 100644
--- a/1-js/9-prototypes/3-native-prototypes/article.md
+++ b/1-js/9-prototypes/3-native-prototypes/article.md
@@ -14,19 +14,26 @@ var obj = { };
alert( obj ); // "[object Object]" ?
```
-В объекте, очевидно, ничего нет... Но кто же тогда генерирует строковое представление для `alert(obj)`?
+Где код, который генерирует строковое представление для `alert(obj)`? Объект-то ведь пустой.
## Object.prototype
-...Конечно же, это сделал метод `toString`, который находится во встроенном прототипе `Object.prototype`. Этот прототип ставится всем объектам `Object` при создании и содержит все встроенные методы и свойства для объектов.
-
-В деталях, работает это так:
+...Конечно же, это сделал метод `toString`, который находится... Конечно, не в самом объекте (он пуст), а в его прототипе `obj.__proto__`, можно его даже вывести:
+
+```js
+//+ run
+alert( {}.__proto__.toString ); // function toString
+```
+
+Откуда новый объект `obj` получает такой `__proto__`?
+
Запись `obj = {}` является краткой формой `obj = new Object`, где `Object` -- встроенная функция-конструктор для объектов.
-
При выполнении `new Object`, создаваемому объекту ставится `__proto__` по `prototype` конструктора, то есть в данном случае `Object.prototype`.
+
При выполнении `new Object`, создаваемому объекту ставится `__proto__` по `prototype` конструктора, который в данном случае равен встроенному `Object.prototype`.
В дальнейшем при обращении к `obj.toString()` -- функция будет взята из `Object.prototype`.
-
+
+
Это можно легко проверить:
@@ -39,26 +46,32 @@ alert(obj.toString == Object.prototype.toString); // true, да
// проверим, правда ли что __proto__ это Object.prototype?
alert(obj.__proto__ == Object.prototype); // true
+
+// А есть ли __proto__ у Object.prototype?
+alert(obj.__proto__.__proto__); // null, нет
```
## Встроенные "классы" в JavaScript
Точно такой же подход используется в массивах `Array`, функциях `Function` и других объектах. Встроенные методы для них находятся в `Array.prototype`, `Function.prototype` и т.п.
-
+
-Как видно из картинки, `Array.prototype` в свою очередь имеет прототипом `Object.prototype`, поэтому если метода нет у массива, то он ищется в объекте.
+Например, когда мы создаём массив, `[1, 2, 3]`, то это альтернативный вариант синтаксиса `new Array`, так что у массивов есть стандартный прототип `Array.prototype`.
-Например, при вызове `arr.hasOwnProperty(...)` для массива `arr` метод `hasOwnProperty` берётся из `Object.prototype`.
+Но в нём есть методы лишь для массивов, а для общих методов всех объектов есть ссылка `Array.prototype.__proto__`, равная `Object.prototype`.
-Получается иерархия наследования, которая всегда заканчивается на `Object.prototype`. Объект `Object.prototype` -- вершина иерархии, единственный, у которого `__proto__` равно `null`.
+Аналогично, для функций.
+
+Лишь для чисел (как и других примитивов) всё немного иначе, но об этом чуть далее.
+
+Объект `Object.prototype` -- вершина иерархии, единственный, у которого `__proto__` равно `null`.
**Поэтому говорят, что "все объекты наследуют от `Object`", а если более точно, то от `Object.prototype`.**
-**"Псевдоклассом" или, более коротко, "классом", называют функцию-конструктор вместе с её `prototype`.**
+"Псевдоклассом" или, более коротко, "классом", называют функцию-конструктор вместе с её `prototype`. Такой способ объявления классов называют "прототипным стилем ООП".
-[smart header="Переопределение методов в наследниках"]
-**При наследовании часть методов переопределяется, например, у массива `Array` есть свой `toString`, который находится в `Array.prototype.toString`:**
+При наследовании часть методов переопределяется, например, у массива `Array` есть свой `toString`, который выводит элементы массива через запятую:
```js
//+ run
@@ -66,12 +79,14 @@ var arr = [1, 2, 3]
alert( arr ); // 1,2,3 <-- результат Array.prototype.toString
```
-Для вывода объекта JavaScript ищет `toString` сначала в самом объекте `arr`, затем в `arr.__proto__`, который равен `Array.prototype`.
+Как мы видели раньше, у `Object.prototype` есть свой `toString`, но так как в `Array.prototype` он ищется первым, то берётся именно вариант для массивов:
-Конечно, если бы его там не было -- поиск пошёл бы выше в `Array.prototype.__proto__`, который по стандарту (см. диаграмму выше) равен `Object.prototype`, и тогда использовался бы стандартный метод для объектов.
-[/smart]
+
-Ранее мы говорили о применении методов массивов к "псевдомассивам", например, можно использовать `[].join` для произвольных объектов, имеющих нумерованные свойства и `length`:
+
+[smart header="Вызов методов через `apply` из прототипа"]
+
+Ранее мы говорили о применении методов массивов к "псевдомассивам", например, можно использовать `[].join` для `arguments`:
```js
//+ run
@@ -97,14 +112,16 @@ function showList() {
showList("Вася", "Паша", "Маша"); // Вася - Паша - Маша
```
-Это лучше, потому что не создаётся лишний объект массива `[]`, хотя, с другой стороны -- так больше писать.
-
+Это эффективнее, потому что не создаётся лишний объект массива `[]`, хотя, с другой стороны -- больше букв писать.
+[/smart]
## Примитивы
Примитивы не являются объектами, но методы берут из соответствующих прототипов: `Number.prototype`, `Boolean.prototype`, `String.prototype`.
-По стандарту, если обратиться к свойству примитива, то будет создан объект соответствующего типа, например `new String`, произведена операция со свойством или вызов метода по обычным правилам, с поиском в прототипе, а затем этот объект будет уничтожен.
+По стандарту, если обратиться к свойству числа, строки или логического значения, то будет создан объект соответствующего типа, например `new String` для строки, `new Number` для чисел, `new Boolean` -- для логических выражений.
+
+Далее будет произведена операция со свойством или вызов метода по обычным правилам, с поиском в прототипе, а затем этот объект будет уничтожен.
Именно так работает код ниже:
@@ -114,17 +131,17 @@ var user = "Вася"; // создали строку (примитив)
*!*
alert( user.toUpperCase() ); // ВАСЯ
-// создан временный объект new String
+// был создан временный объект new String
// вызван метод
// new String уничтожен, результат возвращён
*/!*
```
-**Принципиальное отличие от объектов -- в примитив нельзя записать свойство.**
+Можно даже попробовать записать в этот временный объект свойство:
```js
//+ run
-// а теперь попытаемся записать свойство в строку:
+// попытаемся записать свойство в строку:
var user = "Вася";
user.age = 30;
@@ -133,7 +150,7 @@ alert(user.age); // undefined
*/!*
```
-Свойство `age` было записано во временный объект, который был тут же уничтожен.
+Свойство `age` было записано во временный объект, который был тут же уничтожен, так что смысла в такой записи немного.
[warn header="Конструкторы `String/Number/Boolean` -- только для внутреннего использования"]
Технически, можно создавать объекты для примитивов и вручную, например `new Number`. Но в ряде случаев получится откровенно бредовое поведение. Например:
@@ -163,7 +180,6 @@ if (zero) { // объект - true, так что alert выполнится
Значения `null` и `undefined` стоят особняком. Вышесказанное к ним не относится.
Для них нет соответствующих классов, в них нельзя записать свойство (будет ошибка), в общем, на конкурсе "самое примитивное значение" они точно разделили бы первое место.
-
[/warn]
@@ -194,16 +210,16 @@ Object.prototype.each = function(f) {
}
// Попробуем! (внимание, пока что это работает неверно!)
-var obj = { name: 'Вася', age: 25 };
+var user = { name: 'Вася', age: 25 };
-obj.each(function(prop, val) {
+user.each(function(prop, val) {
alert(prop); // name -> age -> (!) each
});
```
-Обратите внимание -- пример выше работает неправильно. Он выводит лишнее свойство `each`, т.к. цикл `for..in` перебирает свойства в прототипе. Встроенные методы при этом пропускаются, а наш метод -- вылез.
+Обратите внимание -- пример выше работает не совсем корректно. Вместе со свойствами объекта `user` он выводит и наше свойство `each`. Технически, это правильно, так как цикл `for..in` перебирает свойства и в прототипе тоже, но не очень удобно.
-В данном случае это легко поправить добавлением проверки `hasOwnProperty`:
+Конечно, это легко поправить добавлением проверки `hasOwnProperty`:
```js
//+ run
@@ -212,6 +228,7 @@ Object.prototype.each = function(f) {
for (var prop in this) {
*!*
+ // пропускать свойства из прототипа
if (!this.hasOwnProperty(prop)) continue;
*/!*
@@ -230,28 +247,35 @@ obj.each(function(prop, val) {
});
```
-Здесь это сработало, теперь код работает верно. Но мы же не хотим добавлять `hasOwnProperty` в цикл по любому объекту! Поэтому...
+Здесь это сработало, теперь код работает верно. Но мы же не хотим добавлять `hasOwnProperty` в цикл по любому объекту! Поэтому либо не добавляйте свойства в `Object.prototype`, либо можно использовать [дескриптор свойства](/descriptors-getters-setters) и флаг `enumerable`.
+Это, конечно, не будет работать в IE8-:
+```js
+//+ run
+Object.prototype.each = function(f) {
-[warn header="Не добавляйте свойства в `Object.prototype`"]
+ for (var prop in this) {
+ var value = this[prop];
+ f.call(value, prop, value);
+ }
-Свойства, добавленные в `Object.prototype`, появятся во всех `for..in` циклах. Они в них будут лишними.
+};
-[/warn]
+*!*
+// поправить объявление свойства, установив флаг enumerable: false
+Object.defineProperty(Object.prototype, 'each', { enumerable: false });
+*/!*
+// Теперь все будет в порядке
+var obj = { name: 'Вася', age: 25 };
+obj.each(function(prop, val) {
+ alert(prop); // name -> age
+});
+```
-[smart header="Современный стандарт и `for..in`"]
-
-Встроенные свойства и методы не перебираются в `for..in`, так как у них есть специальный внутренний флаг `[[Enumerable]]`, установленный в `false`.
-
-Современные браузеры (включая IE с версии 9) позволяют устанавливать этот флаг для любых свойств, используя специальные вызовы, описанные в главе [](/descriptors-getters-setters). При таком добавлении предупреждение станет неактуальным, так как они тоже не будут видны в `for..in`.
-[/smart]
-
-**Многие объекты не участвуют в циклах `for..in`, например строки, функции... С ними уж точно нет такой проблемы, и в их прототипы, пожалуй, можно добавлять свои методы.**
-
-Но здесь есть свои "за" и "против":
+Есть несколько "за" и "против" модификации встроенных прототипов:
[compare]
+Методы в прототипе автоматически доступны везде, их вызов прост и красив.
@@ -259,7 +283,7 @@ obj.each(function(prop, val) {
-Изменения встроенных прототипов влияют глобально, на все-все скрипты, делать их не очень хорошо с архитектурной точки зрения.
[/compare]
-С другой стороны, есть одно исключение, когда изменения встроенных прототипов не только разрешены, но и приветствуются.
+Как правило, минусы весомее, но есть одно исключение, когда изменения встроенных прототипов не только разрешены, но и приветствуются.
**Допустимо изменение прототипа встроенных объектов, которое добавляет поддержку метода из современных стандартов в те браузеры, где её пока нет.**
diff --git a/1-js/9-prototypes/3-native-prototypes/native-prototype-object.svg b/1-js/9-prototypes/3-native-prototypes/native-prototype-object.svg
new file mode 100644
index 00000000..83e59c12
--- /dev/null
+++ b/1-js/9-prototypes/3-native-prototypes/native-prototype-object.svg
@@ -0,0 +1,40 @@
+
+
+
+ native-prototype-object
+ Created with Sketch.
+
+
+
+
+
+
+ toString: function
+ другие методы объектов
+
+
+ Object.prototype
+
+
+
+
+
+ obj
+
+
+
+
+
+ __proto__
+
+
+
+
+ __proto__
+
+
+ null
+
+
+
+
\ No newline at end of file
diff --git a/1-js/9-prototypes/3-native-prototypes/native-prototypes-array-tostring.svg b/1-js/9-prototypes/3-native-prototypes/native-prototypes-array-tostring.svg
new file mode 100644
index 00000000..091dcd45
--- /dev/null
+++ b/1-js/9-prototypes/3-native-prototypes/native-prototypes-array-tostring.svg
@@ -0,0 +1,48 @@
+
+
+
+ native-prototypes-array-tostring
+ Created with Sketch.
+
+
+
+
+
+
+ toString: function
+ ...
+
+
+ Array.prototype
+
+
+
+
+
+ toString: function
+ ...
+
+
+ Object.prototype
+
+
+
+
+
+
+
+
+ __proto__
+
+
+
+
+ __proto__
+
+
+
+ [1, 2, 3]
+
+
+
+
\ No newline at end of file
diff --git a/1-js/9-prototypes/3-native-prototypes/native-prototypes-classes.svg b/1-js/9-prototypes/3-native-prototypes/native-prototypes-classes.svg
new file mode 100644
index 00000000..24cd6d42
--- /dev/null
+++ b/1-js/9-prototypes/3-native-prototypes/native-prototypes-classes.svg
@@ -0,0 +1,103 @@
+
+
+
+ native-prototypes-classes
+ Created with Sketch.
+
+
+
+
+
+
+ toString: function
+ другие методы объектов
+
+
+ Object.prototype
+
+
+
+
+
+ __proto__
+
+
+
+
+ null
+
+
+
+
+ slice: function
+ другие методы массивов
+
+
+ __proto__
+
+
+ Array.prototype
+
+
+
+
+
+ __proto__
+
+
+ apply: function
+ другие методы функций
+
+
+ Function.prototype
+
+
+
+
+
+ toFixed: function
+ другие методы чисел
+
+
+ Number.prototype
+
+
+ __proto__
+
+
+
+
+
+
+
+
+ [1, 2, 3]
+
+
+
+ function f(args) {
+ ...
+ }
+
+
+
+ 5
+
+
+
+
+ __proto__
+
+
+
+
+ __proto__
+
+
+
+
+ __proto__
+
+
+
+
\ No newline at end of file
diff --git a/1-js/9-prototypes/3-native-prototypes/native-prototypes-object.svg b/1-js/9-prototypes/3-native-prototypes/native-prototypes-object.svg
new file mode 100644
index 00000000..88c49a86
--- /dev/null
+++ b/1-js/9-prototypes/3-native-prototypes/native-prototypes-object.svg
@@ -0,0 +1,40 @@
+
+
+
+ native-prototypes-object
+ Created with Sketch.
+
+
+
+
+
+
+ toString: function
+ другие методы объектов
+
+
+ Object.prototype
+
+
+
+
+
+ obj
+
+
+
+
+
+ __proto__
+
+
+
+
+ __proto__
+
+
+ null
+
+
+
+
\ No newline at end of file
diff --git a/1-js/9-prototypes/4-classes/article.md b/1-js/9-prototypes/4-classes/article.md
index cc6da884..03186252 100644
--- a/1-js/9-prototypes/4-classes/article.md
+++ b/1-js/9-prototypes/4-classes/article.md
@@ -5,9 +5,9 @@
[cut]
## Обычный конструктор
-Вспомним, как мы объявляли конструкторы ранее.
+Вспомним, как мы объявляли классы ранее.
-Например, этот код задаёт объект `Animal` без всяких прототипов:
+Например, этот код задаёт класс `Animal` в функциональном стиле, без всяких прототипов:
```js
//+ run
@@ -38,7 +38,8 @@ animal.stop(); // Зверь стоит
А теперь создадим аналогичный класс, используя прототипы, наподобие того, как сделаны классы `Object`, `Date` и остальные.
-**Чтобы объявить свой класс, нужно:**
+Чтобы объявить свой класс, нужно:
+
Объявить функцию-конструктор.
Записать методы и свойства, нужные всем объектам класса, в `prototype`.
@@ -51,6 +52,7 @@ animal.stop(); // Зверь стоит
// конструктор
function Animal(name) {
this.name = name;
+ this.speed = 0;
}
// методы в прототипе
@@ -64,9 +66,6 @@ Animal.prototype.stop = function() {
alert(this.name + ' стоит');
};
-// свойство speed со значением "по умолчанию"
-Animal.prototype.speed = 0;
-
var animal = new Animal('Зверь');
alert(animal.speed); // 0, свойство взято из прототипа
@@ -75,23 +74,21 @@ animal.run(5); // Зверь бежит, скорость 10
animal.stop(); // Зверь стоит
```
-Здесь объекту `animal` принадлежит лишь свойство `name`, а остальное находится в прототипе.
+В объекте `animal` будут хранится свойства конкретного экземпляра: `name` и `speed`, а общие методы -- в прототипе.
-Обратим внимание, значение `speed` по умолчанию тоже перенесено в прототип, ведь оно во всех объектах (в начале) одинаково, но вызовы `animal.run()`, `animal.stop()` в примере используют вызов `this.speed += speed`, а любая запись в `this.свойство` работает с самим объектом.
-
-То есть, начальное значение `speed` берётся из прототипа, а новое -- пишется уже в сам объект. И в дальнейшем используется.
-
-
+Совершенно такой же подход, как и для встроенных классов в JavaScript.
## Сравнение
-Чем такое задание класса лучше и хуже предыдущего?
+Чем такое задание класса лучше и хуже функционального стиля?
[compare]
-+Прототип позволяет хранить общие свойства и методы в единственном экземпляре, таким образом экономится память и создание объекта происходит быстрее, чем если записывать их в каждый `this`.
--При объявлении класса через прототип, мы теряем возможность использовать локальные переменные и функции.
++Функциональный стиль записывает в каждый объект и свойства и методы, а прототипный -- только свойства. Поэтому прототипный стиль -- быстрее и экономнее по памяти.
+-При создании методов через прототип, мы теряем возможность использовать локальные переменные как приватные свойства, у них больше нет общей области видимости с конструктором.
[/compare]
+Таким образом, прототипный стиль -- быстрее и экономнее, но немного менее удобен.
+
К примеру, есть у нас приватное свойство `name` и метод `sayHi` в функциональном стиле ООП:
```js
@@ -128,11 +125,4 @@ var animal = new Animal("Зверь");
animal.sayHi(); // Зверь
```
-Ранее в каждый объект `Animal` записывалась своя функция `this.sayHi`, а теперь есть одна функция такого рода в прототипе. В сам объект мы пишем только то, что свойственно именно этому объекту.
-
-## Задачи
-
-Обычно свойства по умолчанию хранятся в прототипе. Но если свойство по умолчанию -- объект, то его в прототипе хранить нельзя.
-
-Почему? Смотрите задачу ниже на эту тему.
-
+Впрочем, недостаток этот -- довольно условный. Ведь при наследовании в функциональном стиле также пришлось бы писать `this._name`, чтобы потомок получил доступ к этому значению.
diff --git a/1-js/9-prototypes/6-constructor/2-constructor-inherited/solution.md b/1-js/9-prototypes/5-class-inheritance/6-constructor-inherited/solution.md
similarity index 100%
rename from 1-js/9-prototypes/6-constructor/2-constructor-inherited/solution.md
rename to 1-js/9-prototypes/5-class-inheritance/6-constructor-inherited/solution.md
diff --git a/1-js/9-prototypes/6-constructor/2-constructor-inherited/task.md b/1-js/9-prototypes/5-class-inheritance/6-constructor-inherited/task.md
similarity index 100%
rename from 1-js/9-prototypes/6-constructor/2-constructor-inherited/task.md
rename to 1-js/9-prototypes/5-class-inheritance/6-constructor-inherited/task.md
diff --git a/1-js/9-prototypes/6-constructor/8.png b/1-js/9-prototypes/6-constructor/8.png
deleted file mode 100755
index b875db60..00000000
Binary files a/1-js/9-prototypes/6-constructor/8.png and /dev/null differ
diff --git a/1-js/9-prototypes/6-constructor/8@2x.png b/1-js/9-prototypes/6-constructor/8@2x.png
deleted file mode 100755
index fc77fd69..00000000
Binary files a/1-js/9-prototypes/6-constructor/8@2x.png and /dev/null differ
diff --git a/1-js/9-prototypes/6-constructor/9.png b/1-js/9-prototypes/6-constructor/9.png
deleted file mode 100755
index 666fd19c..00000000
Binary files a/1-js/9-prototypes/6-constructor/9.png and /dev/null differ
diff --git a/1-js/9-prototypes/6-constructor/9@2x.png b/1-js/9-prototypes/6-constructor/9@2x.png
deleted file mode 100755
index 3c193118..00000000
Binary files a/1-js/9-prototypes/6-constructor/9@2x.png and /dev/null differ
diff --git a/1-js/9-prototypes/6-constructor/article.md b/1-js/9-prototypes/6-constructor/article.md
deleted file mode 100644
index 3cc088ac..00000000
--- a/1-js/9-prototypes/6-constructor/article.md
+++ /dev/null
@@ -1,141 +0,0 @@
-# F.prototype по умолчанию, "constructor"
-
-В стандарте JavaScript есть свойство `constructor`, которое, по идее, должно быть в каждом объекте и указывать, какой функцией он создан.
-
-Однако на практике оно ведет себя не всегда адекватным образом. Мы рассмотрим, как оно работает и почему именно так, а также -- как сделать, чтобы оно работало правильно.
-[cut]
-
-## Свойство constructor [#constructor]
-
-По замыслу, свойство `constructor` объекта должно содержать ссылку на функцию, создавшую объект. И в простейших случаях так оно и есть, вот например:
-
-```js
-//+ run
-function Rabbit() { }
-
-var rabbit = new Rabbit();
-
-*!*
-alert( rabbit.constructor == Rabbit ); // true
-*/!*
-```
-
-Как видим, всё работает. Мы получили из объекта функцию, которая его создала.
-
-Но всё не так просто. Расширим наш пример установкой `Rabbit.prototype`:
-
-```js
-//+ run
-function Rabbit() { }
-
-Rabbit.prototype = { jumps: true } ;
-
-var rabbit = new Rabbit();
-
-*!*
-alert( rabbit.constructor == Rabbit ); // false (упс, потеряли конструктор!)
-*/!*
-```
-
-...Сломалось! Чтобы детальнее понять происходящее -- посмотрим, откуда берется свойство `constructor` и что с ним произошло.
-
-## Значение prototype по умолчанию
-
-До этого мы записывали и меняли свойство `prototype`, но оказывается, оно существует и без нашего вмешательства.
-
-**Свойство `prototype` есть у каждой функции, даже если его не ставить.**
-
-**Оно создается автоматически вместе с самой функцией, и по умолчанию является пустым объектом с единственным свойством `constructor`, которое ссылается обратно на функцию.**
-
-Вот такой вид имеет прототип по умолчанию:
-
-```js
-Rabbit.prototype = {
- constructor: Rabbit
-}
-```
-
-
-
-Так что объект `rabbit` не хранит в себе свойство `constructor`, а берёт его из прототипа.
-
-Сделаем прямую проверку этого:
-
-```js
-//+ run
-function Rabbit() { }
-
-var rabbit = new Rabbit();
-
-*!*
-alert( rabbit.hasOwnProperty('constructor') ); // false, в объекте нет!
-
-alert( Rabbit.prototype.hasOwnProperty('constructor') ); // true, да, оно в прототипе
-*/!*
-```
-
-## Потеря constructor
-
-JavaScript не прилагает никаких усилий для проверки корректности или поддержания правильного значения `constructor`.
-
-**При замене `Rabbit.prototype` на свой объект, свойство `constructor` из него обычно пропадает.**
-
-Например:
-
-```js
-//+ run
-function Rabbit() { }
-
-Rabbit.prototype = {}; // (*)
-
-var rabbit = new Rabbit();
-
-alert( rabbit.constructor == Rabbit ); // false
-alert( rabbit.constructor == Object ); // true
-```
-
-Ого! Теперь конструктором `rabbit` является не `Rabbit`, а `Object`. Но почему?
-
-Вот иллюстрация, которая наглядно демонстрирует причину:
-
-
-
-То есть, свойство `constructor` бралось из `Rabbit.prototype`, но мы заменили его на пустой объект `Rabbit.prototype = {}`. В нём свойства `constructor` там уже нет, значит оно ищется дальше по цепочке прототипов, в `{}.__proto__`, то есть берётся из встроенного `Object.prototype`. А там оно равно `Object`.
-
-Что делать?
-
-**Если мы хотим, чтобы свойство `constructor` объекта всегда хранило функцию, которая его создала -- об этом нужно позаботиться самостоятельно.**
-
-То есть, можно не заменять встроенный `Rabbit.prototype`, а расширить его. Или же, если обязательно нужно заменить, скажем при наследовании, то указать `constructor` явно:
-
-```js
-//+ run
-function Animal() { }
-Animal.prototype.run = function() { }
-
-function Rabbit() { }
-*!*
-Rabbit.prototype = Object.create(Animal);
-Rabbit.prototype.constructor = Rabbit;
-*/!*
-
-Rabbit.prototype.run = function() { }
-
-var rabbit = new Rabbit();
-
-*!*
-alert( rabbit.constructor == Rabbit ); // true
-*/!*
-```
-
-## Итого
-
-При создании функции, её `prototype` -- это объект с единственным свойством `constructor`, которое указывает обратно на функцию.
-
-**Забавен тот факт, что больше нигде в спецификации JavaScript свойство `constructor` не упоминается. Интерпретатор не использует его никак и нигде.**
-
-В результате, в частности, `constructor` теряется при замене `prototype` на новый объект. И ничего страшного в этом нет.
-
-Но если мы хотим использовать это свойство сами, чтобы при необходимости получать функцию-конструктор объекта, но при смене прототипа нужно самим смотреть, чтобы ненароком не перезаписать его.
-
-
diff --git a/1-js/9-prototypes/7-instanceof/1-strange-instanceof/solution.md b/1-js/9-prototypes/6-instanceof/1-strange-instanceof/solution.md
similarity index 100%
rename from 1-js/9-prototypes/7-instanceof/1-strange-instanceof/solution.md
rename to 1-js/9-prototypes/6-instanceof/1-strange-instanceof/solution.md
diff --git a/1-js/9-prototypes/7-instanceof/1-strange-instanceof/task.md b/1-js/9-prototypes/6-instanceof/1-strange-instanceof/task.md
similarity index 100%
rename from 1-js/9-prototypes/7-instanceof/1-strange-instanceof/task.md
rename to 1-js/9-prototypes/6-instanceof/1-strange-instanceof/task.md
diff --git a/1-js/9-prototypes/7-instanceof/2-instanceof-result/solution.md b/1-js/9-prototypes/6-instanceof/2-instanceof-result/solution.md
similarity index 100%
rename from 1-js/9-prototypes/7-instanceof/2-instanceof-result/solution.md
rename to 1-js/9-prototypes/6-instanceof/2-instanceof-result/solution.md
diff --git a/1-js/9-prototypes/7-instanceof/2-instanceof-result/task.md b/1-js/9-prototypes/6-instanceof/2-instanceof-result/task.md
similarity index 100%
rename from 1-js/9-prototypes/7-instanceof/2-instanceof-result/task.md
rename to 1-js/9-prototypes/6-instanceof/2-instanceof-result/task.md
diff --git a/1-js/9-prototypes/7-instanceof/article.md b/1-js/9-prototypes/6-instanceof/article.md
similarity index 100%
rename from 1-js/9-prototypes/7-instanceof/article.md
rename to 1-js/9-prototypes/6-instanceof/article.md
diff --git a/1-js/9-prototypes/8-class-extend/article.md b/1-js/9-prototypes/7-class-extend/article.md
similarity index 100%
rename from 1-js/9-prototypes/8-class-extend/article.md
rename to 1-js/9-prototypes/7-class-extend/article.md
diff --git a/1-js/9-prototypes/9-why-prototypes-better/article.md b/1-js/9-prototypes/8-why-prototypes-better/article.md
similarity index 100%
rename from 1-js/9-prototypes/9-why-prototypes-better/article.md
rename to 1-js/9-prototypes/8-why-prototypes-better/article.md