renovations
Before Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 13 KiB |
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
Пример кода (кроме IE10-):
|
Пример кода (кроме IE10-):
|
||||||
|
|
||||||
<div style="position:relative">
|
|
||||||
```js
|
```js
|
||||||
//+ run
|
//+ run
|
||||||
var animal = { eats: true };
|
var animal = { eats: true };
|
||||||
|
@ -27,8 +26,6 @@ rabbit.__proto__ = animal;
|
||||||
alert(rabbit.jumps); // true
|
alert(rabbit.jumps); // true
|
||||||
alert(rabbit.eats); // true
|
alert(rabbit.eats); // true
|
||||||
```
|
```
|
||||||
<div style="position:absolute;left:0;top:0;bottom:0;right:0"><img src="proto-animal-rabbit.svg"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
<li>Первый `alert` здесь работает очевидным образом -- он выводит свойство `jumps` объекта `rabbit`.</li>
|
<li>Первый `alert` здесь работает очевидным образом -- он выводит свойство `jumps` объекта `rabbit`.</li>
|
||||||
|
@ -37,18 +34,7 @@ alert(rabbit.eats); // true
|
||||||
|
|
||||||
Иллюстрация происходящего при чтении `rabbit.eats` (поиск идет снизу вверх):
|
Иллюстрация происходящего при чтении `rabbit.eats` (поиск идет снизу вверх):
|
||||||
|
|
||||||
```js
|
<img src="proto-animal-rabbit.svg">
|
||||||
var animal = {
|
|
||||||
eats: true
|
|
||||||
};
|
|
||||||
|
|
||||||
var rabbit = {
|
|
||||||
jumps: true
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
<img src="1.png">
|
|
||||||
|
|
||||||
**Объект, на который указывает ссылка `__proto__`, называется *"прототипом"*. В данном случае получилось, что `animal` является прототипом для `rabbit`.**
|
**Объект, на который указывает ссылка `__proto__`, называется *"прототипом"*. В данном случае получилось, что `animal` является прототипом для `rabbit`.**
|
||||||
|
|
||||||
|
@ -72,38 +58,16 @@ alert(rabbit.eats); // false, свойство взято из rabbit
|
||||||
|
|
||||||
**Другими словами, прототип -- это "резервное хранилище свойств и методов" объекта, автоматически используемое при поиске.**
|
**Другими словами, прототип -- это "резервное хранилище свойств и методов" объекта, автоматически используемое при поиске.**
|
||||||
|
|
||||||
|
У объекта, который является `__proto__`, может быть свой `__proto__`, у того -- свой, и так далее. При этом свойства будут искаться по цепочке.
|
||||||
|
|
||||||
[smart header="Ссылка __proto__ в спецификации"]
|
[smart header="Ссылка __proto__ в спецификации"]
|
||||||
Если вы будете читать спецификацию EcmaScript -- свойство `__proto__` обозначено в ней как `[[Prototype]]`.
|
Если вы будете читать спецификацию EcmaScript -- свойство `__proto__` обозначено в ней как `[[Prototype]]`.
|
||||||
|
|
||||||
Двойные квадратные скобки здесь важны, чтобы не перепутать его с совсем другим свойством, которое называется `prototype`, и которое мы рассмотрим позже.
|
Двойные квадратные скобки здесь важны, чтобы не перепутать его с совсем другим свойством, которое называется `prototype`, и которое мы рассмотрим позже.
|
||||||
[/smart]
|
[/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
|
|
||||||
*/!*
|
|
||||||
```
|
|
||||||
|
|
||||||
Картина происходящего:
|
|
||||||
|
|
||||||
<img src="donkey_winnie_owl.png">
|
|
||||||
|
|
||||||
## Перебор свойств без прототипа
|
## Метод hasOwnProperty
|
||||||
|
|
||||||
Обычный цикл `for..in` не делает различия между свойствами объекта и его прототипа.
|
Обычный цикл `for..in` не делает различия между свойствами объекта и его прототипа.
|
||||||
|
|
||||||
|
@ -172,28 +136,28 @@ for (var key in rabbit) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Методы для работы с __proto__
|
## Методы для работы с __proto__
|
||||||
|
|
||||||
В современных браузерах есть два дополнительных метода для работы с `__proto__`. Зачем они нужны, если есть `__proto__`? В общем-то, не очень нужны, но по историческим причинам тоже существуют.
|
В современных браузерах есть два дополнительных метода для работы с `__proto__`. Зачем они нужны, если есть `__proto__`? В общем-то, не очень нужны, но по историческим причинам тоже существуют.
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
<dt>[Object.getPrototypeOf(obj)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/getPrototypeOf)</dt>
|
<dt>Чтение: [Object.getPrototypeOf(obj)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/getPrototypeOf)</dt>
|
||||||
<dd>Возвращает `obj.__proto__` (кроме IE8-)</dd>
|
<dd>Возвращает `obj.__proto__` (кроме IE8-)</dd>
|
||||||
<dt>[Object.setPrototypeOf(obj, proto)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/setPrototypeOf)</dt>
|
<dt>Запись: [Object.setPrototypeOf(obj, proto)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/setPrototypeOf)</dt>
|
||||||
<dd>Устанавливает `obj.__proto__ = proto` (кроме IE10-).</dd>
|
<dd>Устанавливает `obj.__proto__ = proto` (кроме IE10-).</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
Кроме того, есть ещё один вспомогательный метод:
|
Кроме того, есть ещё один вспомогательный метод:
|
||||||
<dt>[Object.create(proto)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create)</dt>
|
<dt>Создание объекта с прототипом: [Object.create(proto, descriptors)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create)</dt>
|
||||||
<dd>Создаёт пустой объект с `__proto__`, равным первому аргументу (кроме IE8-).</dd>
|
<dd>Создаёт пустой объект с `__proto__`, равным первому аргументу (кроме IE8-), второй необязательный аргумент может содержать [дескрипторы свойств](/descriptors-getters-setters).</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
Метод `Object.create` -- несколько более мощный, чем здесь описано, у него есть необязательный второй аргумент, который позволяет также задать другие свойства объекта, но используется он редко и пока что нам не нужен. Мы рассмотрим его позже, в главе [](/descriptors-getters-setters).
|
|
||||||
|
|
||||||
## Итого
|
## Итого
|
||||||
|
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>Объекты в JavaScript можно организовать в цепочку при помощи специального свойства `__proto__`.</li>
|
<li>В JavaScript есть встроенное "наследование" между объектами при помощи специального свойства `__proto__`.</li>
|
||||||
<li>При установке свойства `rabbit.__proto__ = animal` говорят, что объект `animal` будет "прототипом" `rabbit`.</li>
|
<li>При установке свойства `rabbit.__proto__ = animal` говорят, что объект `animal` будет "прототипом" `rabbit`.</li>
|
||||||
<li>При чтении свойства из объекта, если его в нём нет, оно ищется в `__proto__`. Прототип задействуется только при чтении свойства. Операции присвоения `obj.prop =` или удаления `delete obj.prop` совершаются всегда над самим объектом `obj`.</li>
|
<li>При чтении свойства из объекта, если его в нём нет, оно ищется в `__proto__`. Прототип задействуется только при чтении свойства. Операции присвоения `obj.prop =` или удаления `delete obj.prop` совершаются всегда над самим объектом `obj`.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -205,12 +169,12 @@ for (var key in rabbit) {
|
||||||
<ul>
|
<ul>
|
||||||
<li>[Object.getPrototypeOf(obj)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/getPrototypeOf) (кроме IE8-)</li>
|
<li>[Object.getPrototypeOf(obj)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/getPrototypeOf) (кроме IE8-)</li>
|
||||||
<li>[Object.setPrototypeOf(obj, proto)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/setPrototypeOf) (кроме IE10-)</li>
|
<li>[Object.setPrototypeOf(obj, proto)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/setPrototypeOf) (кроме IE10-)</li>
|
||||||
<li>[Object.create(proto)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create) (кроме IE8-)</li>
|
<li>[Object.create(proto, descriptors)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create) (кроме IE8-)</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
Возможно, вас смущает недостаточная поддержка `__proto__` в старых IE. Но это временно. В последующих главах мы рассмотрим дополнительные методы работы с `__proto__`, включая те, которые работают везде.
|
Возможно, вас смущает недостаточная поддержка `__proto__` в старых IE. Но это не страшно. В последующих главах мы рассмотрим дополнительные методы работы с `__proto__`, включая те, которые работают везде.
|
||||||
|
|
||||||
Также мы рассмотрим, как свойство `__proto__` используется внутри самого языка JavaScript.
|
Также мы рассмотрим, как свойство `__proto__` используется внутри самого языка JavaScript и как организовать классы с его помощью.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 301 KiB |
|
@ -1,22 +1,34 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<svg width="347px" height="163px" viewBox="0 0 347 163" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
<svg width="140px" height="136px" viewBox="0 0 140 136" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||||
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
||||||
<title>proto-animal-rabbit</title>
|
<title>proto-animal-rabbit</title>
|
||||||
<desc>Created with Sketch.</desc>
|
<desc>Created with Sketch.</desc>
|
||||||
<defs></defs>
|
<defs></defs>
|
||||||
<g id="proto-animal-rabbit" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
<g id="proto-animal-rabbit" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||||
<g sketch:type="MSLayerGroup">
|
<g sketch:type="MSLayerGroup" transform="translate(0.000000, 1.000000)">
|
||||||
<rect id="Rectangle-1" opacity="0.01" fill="#979797" sketch:type="MSShapeGroup" x="0" y="0" width="347" height="163"></rect>
|
<g id="Rectangle-1-+-eats:-true-+-animal">
|
||||||
<g id="Line-+-Line-+-Line" transform="translate(275.000000, 40.000000)" stroke="#D0011B" stroke-linecap="square" sketch:type="MSShapeGroup">
|
<rect id="Rectangle-1" stroke="#979797" sketch:type="MSShapeGroup" x="0" y="17" width="120" height="30"></rect>
|
||||||
<path d="M0.5,101.514286 C0.5,101.514286 39.4570312,96.9360491 39.4570312,51.4857143 C39.4570312,6.03537946 0.5,1.45714286 0.5,1.45714286" id="Line"></path>
|
<text id="eats:-true" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
<path d="M0.5,1.45714286 L10.5,9.22857143" id="Line"></path>
|
<tspan x="11" y="35">eats: true</tspan>
|
||||||
<path d="M0.5,1.45714286 L13.5,1.45714286" id="Line"></path>
|
</text>
|
||||||
|
<text id="animal" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-style="italic" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="0" y="10">animal</tspan>
|
||||||
|
</text>
|
||||||
</g>
|
</g>
|
||||||
<g id="Line-+-Line-+-Line-2" transform="translate(274.000000, 17.000000)" stroke="#D0011B" stroke-linecap="square" sketch:type="MSShapeGroup">
|
<g id="Rectangle-1-+-eats:-true-+-animal-2" transform="translate(0.000000, 88.000000)">
|
||||||
<path d="M0.5,2.45714286 L10.5,10.2285714" id="Line-3"></path>
|
<rect id="Rectangle-1" stroke="#979797" sketch:type="MSShapeGroup" x="0" y="17" width="120" height="30"></rect>
|
||||||
<path d="M1.1875,19.9190476 C1.1875,19.9190476 15.7963867,19.1220178 15.7963867,11.2095238 C15.7963867,3.29702977 1.1875,2.5 1.1875,2.5" id="Line"></path>
|
<text id="jumps:-true" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
<path d="M1.5,2.45714286 L12.5,0.5" id="Line-2"></path>
|
<tspan x="11" y="35">jumps: true</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="rabbit" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-style="italic" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="0" y="10">rabbit</tspan>
|
||||||
|
</text>
|
||||||
</g>
|
</g>
|
||||||
|
<path d="M60.5,96.5 L60.5,55.5" id="Line" stroke="#4990E2" stroke-linecap="square" fill="#4990E2" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path id="Line-decoration-1" d="M60.5,55.5 C59.45,59.28 58.55,62.52 57.5,66.3 C59.6,66.3 61.4,66.3 63.5,66.3 C62.45,62.52 61.55,59.28 60.5,55.5 C60.5,55.5 60.5,55.5 60.5,55.5 Z" stroke="#4990E2" stroke-linecap="square" fill="#4990E2"></path>
|
||||||
|
<text id="__proto__" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="70" y="77">__proto__</tspan>
|
||||||
|
</text>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.6 KiB |
|
@ -16,4 +16,19 @@ alert(obj2.name); // Петя (сработало)
|
||||||
|
|
||||||
Сработало, так как `User.prototype.constructor == User`.
|
Сработало, так как `User.prototype.constructor == User`.
|
||||||
|
|
||||||
Но если кто-то, к примеру, перезапишет `User.prototype` и забудет указать `constructor`, то такой фокус не пройдёт.
|
Но если кто-то, к примеру, перезапишет `User.prototype` и забудет указать `constructor`, то такой фокус не пройдёт, например:
|
||||||
|
|
||||||
|
```js
|
||||||
|
//+ run
|
||||||
|
function User(name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
*!*
|
||||||
|
User.prototype = {};
|
||||||
|
*/!*
|
||||||
|
|
||||||
|
var obj = new User('Вася');
|
||||||
|
var obj2 = new obj.constructor('Петя');
|
||||||
|
|
||||||
|
alert(obj2.name); // undefined
|
||||||
|
```
|
|
@ -10,4 +10,4 @@
|
||||||
var obj2 = new obj.constructor();
|
var obj2 = new obj.constructor();
|
||||||
```
|
```
|
||||||
|
|
||||||
В каком случае такой код будет работать, а в каком -- нет?
|
Приведите пример конструкторов для `obj`, при которых такой код будет работать верно -- и неверно.
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
До этого момента мы говорили о наследовании объектов, объявленных через `{...}`.
|
До этого момента мы говорили о наследовании объектов, объявленных через `{...}`.
|
||||||
|
|
||||||
Но что, если объекты создаются функцией-конструктором через `new`? Как указать прототип в этом случае?
|
Но в реальных проектах объекты обычно создаются функцией-конструктором через `new`. Посмотрим, как указать прототип в этом случае.
|
||||||
[cut]
|
[cut]
|
||||||
|
|
||||||
## Свойство F.prototype
|
## Свойство F.prototype
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//+ run
|
//+ run
|
||||||
var animal = { eats: true }
|
var animal = { eats: true };
|
||||||
|
|
||||||
function Rabbit(name) {
|
function Rabbit(name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -57,9 +57,9 @@ alert( rabbit.eats ); // true
|
||||||
Установка `Rabbit.prototype = animal` буквально говорит интерпретатору следующее: *"При создании объекта через `new Rabbit` запиши ему `__proto__ = animal`".*
|
Установка `Rabbit.prototype = animal` буквально говорит интерпретатору следующее: *"При создании объекта через `new Rabbit` запиши ему `__proto__ = animal`".*
|
||||||
|
|
||||||
[smart header="Свойство `prototype` имеет смысл только у конструктора"]
|
[smart header="Свойство `prototype` имеет смысл только у конструктора"]
|
||||||
Свойство `prototype` можно указать на любом объекте, но особый смысл оно имеет, лишь если назначено функции-конструктору.
|
Свойство с именем `prototype` можно указать на любом объекте, но особый смысл оно имеет, лишь если назначено функции-конструктору.
|
||||||
|
|
||||||
Само по себе оно вообще ничего не делает, его единственное назначение -- ставить `__proto__` новым объектам.
|
Само по себе, без вызова оператора `new`, оно вообще ничего не делает, его единственное назначение -- указывать `__proto__` для новых объектов.
|
||||||
[/smart]
|
[/smart]
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,15 +70,81 @@ alert( rabbit.eats ); // true
|
||||||
Однако, при работе `new`, свойство `prototype` будет использовано лишь в том случае, если это объект. Примитивное значение, такое как число или строка, будет проигнорировано.
|
Однако, при работе `new`, свойство `prototype` будет использовано лишь в том случае, если это объект. Примитивное значение, такое как число или строка, будет проигнорировано.
|
||||||
[/warn]
|
[/warn]
|
||||||
|
|
||||||
|
## Свойство constructor
|
||||||
|
|
||||||
|
У каждой функции по умолчанию уже есть свойство `prototype`.
|
||||||
|
|
||||||
|
Оно содержит объект такого вида:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function Rabbit() { }
|
||||||
|
|
||||||
|
Rabbit.prototype = {
|
||||||
|
constructor: Rabbit
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
В коде выше я создал `Rabbit.prototype` вручную, но ровно такой же -- генерируется автоматически.
|
||||||
|
|
||||||
|
Проверим:
|
||||||
|
|
||||||
|
```js
|
||||||
|
//+ run
|
||||||
|
function Rabbit() { }
|
||||||
|
|
||||||
|
// в Rabbit.prototype есть одно свойство: constructor
|
||||||
|
alert(Object.getOwnPropertyNames(Rabbit.prototype)); // constructor
|
||||||
|
|
||||||
|
// оно равно Rabbit
|
||||||
|
alert(Rabbit.prototype.constructor == Rabbit); // true
|
||||||
|
```
|
||||||
|
|
||||||
|
Можно его использовать для создания объекта с тем же конструктором, что и данный:
|
||||||
|
|
||||||
|
```js
|
||||||
|
//+ run
|
||||||
|
function Rabbit(name) {
|
||||||
|
this.name = name;
|
||||||
|
alert(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
var rabbit = new Rabbit("Кроль");
|
||||||
|
|
||||||
|
var rabbit2 = new rabbit.constructor("Крольчиха");
|
||||||
|
```
|
||||||
|
|
||||||
|
Эта возможность бывает полезна, когда, получив объект, мы не знаем в точности, какой у него был конструктор (например, сделан вне нашего кода), а нужно создать такой же.
|
||||||
|
|
||||||
|
[warn header="Свойство `constructor` легко потерять"]
|
||||||
|
JavaScript никак не использует свойство `constructor`. То есть, оно создаётся автоматически, а что с ним происходит дальше -- это уже наша забота. В стандарте прописано только его создание.
|
||||||
|
|
||||||
|
В частности, при перезаписи `Rabbit.prototype = { jumps: true }` свойства `constructor` больше не будет.
|
||||||
|
|
||||||
|
Сам интерпретатор JavaScript его в служебных целях не требует, поэтому в работе объектов ничего не "сломается". Но если мы хотим, чтобы возможность получить конструктор, всё же, была, то можно при перезаписи гарантировать наличие `constructor` вручную:
|
||||||
|
```js
|
||||||
|
Rabbit.prototype = {
|
||||||
|
jumps: true,
|
||||||
|
*!*
|
||||||
|
constructor: Rabbit
|
||||||
|
*/!*
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Либо можно поступить аккуратно и добавить свойства к встроенному `prototype` без его замены:
|
||||||
|
```js
|
||||||
|
// сохранится встроенный constructor
|
||||||
|
Rabbit.prototype.jumps = true
|
||||||
|
```
|
||||||
|
[/warn]
|
||||||
|
|
||||||
|
|
||||||
## Эмуляция Object.create для IE8- [#inherit]
|
## Эмуляция Object.create для IE8- [#inherit]
|
||||||
|
|
||||||
Как мы только что видели, с конструкторами всё просто, назначить прототип можно кросс-браузерно при помощи `F.prototype`.
|
Как мы только что видели, с конструкторами всё просто, назначить прототип можно кросс-браузерно при помощи `F.prototype`.
|
||||||
|
|
||||||
Теперь вернёмся к созданию объектов без конструктора.
|
Теперь небольшое "лирическое отступление" в область совместимости.
|
||||||
|
|
||||||
Мы знаем, что в этом случае можно указывать прототип при помощи `__proto__`, но это не работает в IE10-. Также мы знаем, что есть метод `Object.create(proto)`, который создаёт пустой объект с данным прототипом, но он не работает в IE8-.
|
Прямые методы работы с прототипом осутствуют в старых IE, но один из них -- `Object.create(proto)` можно эмулировать, как раз при помощи `prototype`. И он будет работать везде, даже в самых устаревших браузерах.
|
||||||
|
|
||||||
**Используя `prototype`, вызов `Object.create` можно легко эмулировать, так что он будет работать во всех браузерах, включая даже очень-очень старые.**
|
|
||||||
|
|
||||||
Кросс-браузерный аналог -- назовём его `inherit`, состоит буквально из нескольких строк:
|
Кросс-браузерный аналог -- назовём его `inherit`, состоит буквально из нескольких строк:
|
||||||
|
|
||||||
|
@ -91,7 +157,7 @@ function inherit(proto) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Результат вызова `inherit(animal)` идентичен `Object.create(animal)`. Это будет новый пустой объект с прототипом `animal`.
|
Результат вызова `inherit(animal)` идентичен `Object.create(animal)`. Она создаёт новый пустой объект с прототипом `animal`.
|
||||||
|
|
||||||
Например:
|
Например:
|
||||||
|
|
||||||
|
@ -106,7 +172,7 @@ alert(rabbit.eats); // true
|
||||||
|
|
||||||
Посмотрите внимательно на функцию `inherit` и вы, наверняка, сами поймёте, как она работает...
|
Посмотрите внимательно на функцию `inherit` и вы, наверняка, сами поймёте, как она работает...
|
||||||
|
|
||||||
Давайте, на всякий случай, пройдём её по шагам:
|
Если где-то неясности, то её построчное описание:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
function inherit(proto) {
|
function inherit(proto) {
|
||||||
|
@ -124,10 +190,7 @@ function inherit(proto) {
|
||||||
<li>Мы получили пустой объект с заданным прототипом, как и хотели. Возвратим его.</li>
|
<li>Мы получили пустой объект с заданным прототипом, как и хотели. Возвратим его.</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
|
Для унификации можно запустить такой код, и метод `Object.create` станет кросс-браузерным:
|
||||||
Эта функция широко используется в библиотеках и фреймворках.
|
|
||||||
|
|
||||||
Здесь и далее мы будем использовать `Object.create`, предполагая что для IE8- выполнен код:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
if (!Object.create) Object.create = inherit; /* определение inherit - выше */
|
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` станет доступен для всех браузеров.
|
В частности, аналогичным образом работает библиотека [es5-shim](https://github.com/es-shims/es5-shim), при подключении которой `Object.create` станет доступен для всех браузеров.
|
||||||
|
|
||||||
|
|
||||||
## Итого
|
## Итого
|
||||||
|
|
||||||
|
Для произвольной функции -- назовём её `Constructor`, верно следующее:
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>Прототип новых объектов, создаваемых через `new`, можно задавать кросс-браузерно, при помощи свойства конструктора `prototype`.</li>
|
<li>Прототип `__proto__` новых объектов, создаваемых через `new Constructor`, можно задавать при помощи свойства `Constructor.prototype`.</li>
|
||||||
<li>При создании объекта через `new F`, в его `__proto__` записывается ссылка на объект `F.prototype`.</li>
|
<li>Значением `Constructor.prototype` по умолчанию является объект с единственным свойством `constructor`, содержащим ссылку на `Constructor`. Его можно использовать, чтобы из самого объекта получить функцию, которая его создала. Однако, JavaScript никак не поддерживает корректность этого свойства, поэтому программист может его изменить или удалить.</li>
|
||||||
<li>Современный метод `Object.create(proto)` можно эмулировать его при помощи `prototype`, если хочется, чтобы он работал в IE8-.</li>
|
<li>Современный метод `Object.create(proto)` можно эмулировать при помощи `prototype`, если хочется, чтобы он работал в IE8-.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 63 KiB |
|
@ -14,19 +14,26 @@ var obj = { };
|
||||||
alert( obj ); // "[object Object]" ?
|
alert( obj ); // "[object Object]" ?
|
||||||
```
|
```
|
||||||
|
|
||||||
В объекте, очевидно, ничего нет... Но кто же тогда генерирует строковое представление для `alert(obj)`?
|
Где код, который генерирует строковое представление для `alert(obj)`? Объект-то ведь пустой.
|
||||||
|
|
||||||
## Object.prototype
|
## Object.prototype
|
||||||
|
|
||||||
...Конечно же, это сделал метод `toString`, который находится во встроенном прототипе `Object.prototype`. Этот прототип ставится всем объектам `Object` при создании и содержит все встроенные методы и свойства для объектов.
|
...Конечно же, это сделал метод `toString`, который находится... Конечно, не в самом объекте (он пуст), а в его прототипе `obj.__proto__`, можно его даже вывести:
|
||||||
|
|
||||||
В деталях, работает это так:
|
```js
|
||||||
|
//+ run
|
||||||
|
alert( {}.__proto__.toString ); // function toString
|
||||||
|
```
|
||||||
|
|
||||||
|
Откуда новый объект `obj` получает такой `__proto__`?
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
<li>Запись `obj = {}` является краткой формой `obj = new Object`, где `Object` -- встроенная функция-конструктор для объектов.</li>
|
<li>Запись `obj = {}` является краткой формой `obj = new Object`, где `Object` -- встроенная функция-конструктор для объектов.</li>
|
||||||
<li>При выполнении `new Object`, создаваемому объекту ставится `__proto__` по `prototype` конструктора, то есть в данном случае `Object.prototype`.</li>
|
<li>При выполнении `new Object`, создаваемому объекту ставится `__proto__` по `prototype` конструктора, который в данном случае равен встроенному `Object.prototype`.</li>
|
||||||
<li>В дальнейшем при обращении к `obj.toString()` -- функция будет взята из `Object.prototype`.</li>
|
<li>В дальнейшем при обращении к `obj.toString()` -- функция будет взята из `Object.prototype`.</li>
|
||||||
</ol>
|
</ol>
|
||||||
<img src="5.png">
|
|
||||||
|
<img src="native-prototypes-object.svg">
|
||||||
|
|
||||||
Это можно легко проверить:
|
Это можно легко проверить:
|
||||||
|
|
||||||
|
@ -39,26 +46,32 @@ alert(obj.toString == Object.prototype.toString); // true, да
|
||||||
|
|
||||||
// проверим, правда ли что __proto__ это Object.prototype?
|
// проверим, правда ли что __proto__ это Object.prototype?
|
||||||
alert(obj.__proto__ == Object.prototype); // true
|
alert(obj.__proto__ == Object.prototype); // true
|
||||||
|
|
||||||
|
// А есть ли __proto__ у Object.prototype?
|
||||||
|
alert(obj.__proto__.__proto__); // null, нет
|
||||||
```
|
```
|
||||||
|
|
||||||
## Встроенные "классы" в JavaScript
|
## Встроенные "классы" в JavaScript
|
||||||
|
|
||||||
Точно такой же подход используется в массивах `Array`, функциях `Function` и других объектах. Встроенные методы для них находятся в `Array.prototype`, `Function.prototype` и т.п.
|
Точно такой же подход используется в массивах `Array`, функциях `Function` и других объектах. Встроенные методы для них находятся в `Array.prototype`, `Function.prototype` и т.п.
|
||||||
|
|
||||||
<img src="6.png">
|
<img src="native-prototypes-classes.svg">
|
||||||
|
|
||||||
Как видно из картинки, `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`.**
|
**Поэтому говорят, что "все объекты наследуют от `Object`", а если более точно, то от `Object.prototype`.**
|
||||||
|
|
||||||
**"Псевдоклассом" или, более коротко, "классом", называют функцию-конструктор вместе с её `prototype`.**
|
"Псевдоклассом" или, более коротко, "классом", называют функцию-конструктор вместе с её `prototype`. Такой способ объявления классов называют "прототипным стилем ООП".
|
||||||
|
|
||||||
[smart header="Переопределение методов в наследниках"]
|
При наследовании часть методов переопределяется, например, у массива `Array` есть свой `toString`, который выводит элементы массива через запятую:
|
||||||
**При наследовании часть методов переопределяется, например, у массива `Array` есть свой `toString`, который находится в `Array.prototype.toString`:**
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//+ run
|
//+ run
|
||||||
|
@ -66,12 +79,14 @@ var arr = [1, 2, 3]
|
||||||
alert( arr ); // 1,2,3 <-- результат Array.prototype.toString
|
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`, и тогда использовался бы стандартный метод для объектов.
|
<img src="native-prototypes-array-tostring.svg">
|
||||||
[/smart]
|
|
||||||
|
|
||||||
Ранее мы говорили о применении методов массивов к "псевдомассивам", например, можно использовать `[].join` для произвольных объектов, имеющих нумерованные свойства и `length`:
|
|
||||||
|
[smart header="Вызов методов через `apply` из прототипа"]
|
||||||
|
|
||||||
|
Ранее мы говорили о применении методов массивов к "псевдомассивам", например, можно использовать `[].join` для `arguments`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//+ run
|
//+ run
|
||||||
|
@ -97,14 +112,16 @@ function showList() {
|
||||||
showList("Вася", "Паша", "Маша"); // Вася - Паша - Маша
|
showList("Вася", "Паша", "Маша"); // Вася - Паша - Маша
|
||||||
```
|
```
|
||||||
|
|
||||||
Это лучше, потому что не создаётся лишний объект массива `[]`, хотя, с другой стороны -- так больше писать.
|
Это эффективнее, потому что не создаётся лишний объект массива `[]`, хотя, с другой стороны -- больше букв писать.
|
||||||
|
[/smart]
|
||||||
|
|
||||||
## Примитивы
|
## Примитивы
|
||||||
|
|
||||||
Примитивы не являются объектами, но методы берут из соответствующих прототипов: `Number.prototype`, `Boolean.prototype`, `String.prototype`.
|
Примитивы не являются объектами, но методы берут из соответствующих прототипов: `Number.prototype`, `Boolean.prototype`, `String.prototype`.
|
||||||
|
|
||||||
По стандарту, если обратиться к свойству примитива, то будет создан объект соответствующего типа, например `new String`, произведена операция со свойством или вызов метода по обычным правилам, с поиском в прототипе, а затем этот объект будет уничтожен.
|
По стандарту, если обратиться к свойству числа, строки или логического значения, то будет создан объект соответствующего типа, например `new String` для строки, `new Number` для чисел, `new Boolean` -- для логических выражений.
|
||||||
|
|
||||||
|
Далее будет произведена операция со свойством или вызов метода по обычным правилам, с поиском в прототипе, а затем этот объект будет уничтожен.
|
||||||
|
|
||||||
Именно так работает код ниже:
|
Именно так работает код ниже:
|
||||||
|
|
||||||
|
@ -114,17 +131,17 @@ var user = "Вася"; // создали строку (примитив)
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
alert( user.toUpperCase() ); // ВАСЯ
|
alert( user.toUpperCase() ); // ВАСЯ
|
||||||
// создан временный объект new String
|
// был создан временный объект new String
|
||||||
// вызван метод
|
// вызван метод
|
||||||
// new String уничтожен, результат возвращён
|
// new String уничтожен, результат возвращён
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
**Принципиальное отличие от объектов -- в примитив нельзя записать свойство.**
|
Можно даже попробовать записать в этот временный объект свойство:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//+ run
|
//+ run
|
||||||
// а теперь попытаемся записать свойство в строку:
|
// попытаемся записать свойство в строку:
|
||||||
var user = "Вася";
|
var user = "Вася";
|
||||||
user.age = 30;
|
user.age = 30;
|
||||||
|
|
||||||
|
@ -133,7 +150,7 @@ alert(user.age); // undefined
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
Свойство `age` было записано во временный объект, который был тут же уничтожен.
|
Свойство `age` было записано во временный объект, который был тут же уничтожен, так что смысла в такой записи немного.
|
||||||
|
|
||||||
[warn header="Конструкторы `String/Number/Boolean` -- только для внутреннего использования"]
|
[warn header="Конструкторы `String/Number/Boolean` -- только для внутреннего использования"]
|
||||||
Технически, можно создавать объекты для примитивов и вручную, например `new Number`. Но в ряде случаев получится откровенно бредовое поведение. Например:
|
Технически, можно создавать объекты для примитивов и вручную, например `new Number`. Но в ряде случаев получится откровенно бредовое поведение. Например:
|
||||||
|
@ -163,7 +180,6 @@ if (zero) { // объект - true, так что alert выполнится
|
||||||
Значения `null` и `undefined` стоят особняком. Вышесказанное к ним не относится.
|
Значения `null` и `undefined` стоят особняком. Вышесказанное к ним не относится.
|
||||||
|
|
||||||
Для них нет соответствующих классов, в них нельзя записать свойство (будет ошибка), в общем, на конкурсе "самое примитивное значение" они точно разделили бы первое место.
|
Для них нет соответствующих классов, в них нельзя записать свойство (будет ошибка), в общем, на конкурсе "самое примитивное значение" они точно разделили бы первое место.
|
||||||
|
|
||||||
[/warn]
|
[/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
|
alert(prop); // name -> age -> (!) each
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Обратите внимание -- пример выше работает неправильно. Он выводит лишнее свойство `each`, т.к. цикл `for..in` перебирает свойства в прототипе. Встроенные методы при этом пропускаются, а наш метод -- вылез.
|
Обратите внимание -- пример выше работает не совсем корректно. Вместе со свойствами объекта `user` он выводит и наше свойство `each`. Технически, это правильно, так как цикл `for..in` перебирает свойства и в прототипе тоже, но не очень удобно.
|
||||||
|
|
||||||
В данном случае это легко поправить добавлением проверки `hasOwnProperty`:
|
Конечно, это легко поправить добавлением проверки `hasOwnProperty`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//+ run
|
//+ run
|
||||||
|
@ -212,6 +228,7 @@ Object.prototype.each = function(f) {
|
||||||
for (var prop in this) {
|
for (var prop in this) {
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
|
// пропускать свойства из прототипа
|
||||||
if (!this.hasOwnProperty(prop)) continue;
|
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]
|
[compare]
|
||||||
+Методы в прототипе автоматически доступны везде, их вызов прост и красив.
|
+Методы в прототипе автоматически доступны везде, их вызов прост и красив.
|
||||||
|
@ -259,7 +283,7 @@ obj.each(function(prop, val) {
|
||||||
-Изменения встроенных прототипов влияют глобально, на все-все скрипты, делать их не очень хорошо с архитектурной точки зрения.
|
-Изменения встроенных прототипов влияют глобально, на все-все скрипты, делать их не очень хорошо с архитектурной точки зрения.
|
||||||
[/compare]
|
[/compare]
|
||||||
|
|
||||||
С другой стороны, есть одно исключение, когда изменения встроенных прототипов не только разрешены, но и приветствуются.
|
Как правило, минусы весомее, но есть одно исключение, когда изменения встроенных прототипов не только разрешены, но и приветствуются.
|
||||||
|
|
||||||
**Допустимо изменение прототипа встроенных объектов, которое добавляет поддержку метода из современных стандартов в те браузеры, где её пока нет.**
|
**Допустимо изменение прототипа встроенных объектов, которое добавляет поддержку метода из современных стандартов в те браузеры, где её пока нет.**
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="200px" height="233px" viewBox="0 0 200 233" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||||
|
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>native-prototype-object</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="native-prototype-object" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||||
|
<g sketch:type="MSLayerGroup">
|
||||||
|
<g id="Rectangle-1-+-eats:-true-+-animal" transform="translate(0.000000, 69.000000)">
|
||||||
|
<rect id="Rectangle-1" stroke="#979797" sketch:type="MSShapeGroup" x="0" y="17" width="200" height="60"></rect>
|
||||||
|
<text id="toString:-function" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="11" y="41">toString: function</tspan>
|
||||||
|
<tspan x="11" y="57">другие методы объектов</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="Object.prototype" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-style="italic" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="0" y="10">Object.prototype</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
<g id="Rectangle-1-+-eats:-true-+-animal-2" transform="translate(0.000000, 186.000000)">
|
||||||
|
<rect id="Rectangle-1" stroke="#979797" sketch:type="MSShapeGroup" x="0" y="17" width="200" height="30"></rect>
|
||||||
|
<text id="obj" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-style="italic" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="0" y="10">obj</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
<path d="M60.5,194.5 L60.5,153.5" id="Line" stroke="#4990E2" stroke-linecap="square" fill="#4990E2" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path id="Line-decoration-1" d="M60.5,153.5 C59.45,157.28 58.55,160.52 57.5,164.3 C59.6,164.3 61.4,164.3 63.5,164.3 C62.45,160.52 61.55,157.28 60.5,153.5 C60.5,153.5 60.5,153.5 60.5,153.5 Z" stroke="#4990E2" stroke-linecap="square" fill="#4990E2"></path>
|
||||||
|
<text id="__proto__" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="70" y="175">__proto__</tspan>
|
||||||
|
</text>
|
||||||
|
<path d="M60.5,62.5 L60.5,21.5" id="Line-2" stroke="#4990E2" stroke-linecap="square" fill="#4990E2" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path id="Line-2-decoration-1" d="M60.5,21.5 C59.45,25.28 58.55,28.52 57.5,32.3 C59.6,32.3 61.4,32.3 63.5,32.3 C62.45,28.52 61.55,25.28 60.5,21.5 C60.5,21.5 60.5,21.5 60.5,21.5 Z" stroke="#4990E2" stroke-linecap="square" fill="#4990E2"></path>
|
||||||
|
<text id="__proto__-2" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="70" y="43">__proto__</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="null" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="46" y="10">null</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="201px" height="298px" viewBox="0 0 201 298" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||||
|
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>native-prototypes-array-tostring</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="native-prototypes-array-tostring" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||||
|
<g sketch:type="MSLayerGroup" transform="translate(1.000000, 1.000000)">
|
||||||
|
<g id="Rectangle-1-+-eats:-true-+-animal" transform="translate(0.000000, 133.000000)">
|
||||||
|
<rect id="Rectangle-1" stroke="#979797" sketch:type="MSShapeGroup" x="0" y="17" width="200" height="60"></rect>
|
||||||
|
<text id="toString:-function" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="11" y="41">toString: function</tspan>
|
||||||
|
<tspan x="11" y="57">...</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="Array.prototype" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-style="italic" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="0" y="10">Array.prototype</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
<g id="Rectangle-1-+-eats:-true-+-animal-3">
|
||||||
|
<rect id="Rectangle-1" stroke="#979797" sketch:type="MSShapeGroup" x="0" y="17" width="200" height="60"></rect>
|
||||||
|
<text id="toString:-function" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="11" y="41">toString: function</tspan>
|
||||||
|
<tspan x="11" y="57">...</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="Object.prototype" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-style="italic" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="0" y="10">Object.prototype</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
<g id="Rectangle-1-+-eats:-true-+-animal-2" transform="translate(0.000000, 267.000000)" stroke="#979797" sketch:type="MSShapeGroup">
|
||||||
|
<rect id="Rectangle-1" x="0" y="0" width="200" height="30"></rect>
|
||||||
|
</g>
|
||||||
|
<path d="M60.5,258.5 L60.5,217.5" id="Line" stroke="#4990E2" stroke-linecap="square" fill="#4990E2" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path id="Line-decoration-1" d="M60.5,217.5 C59.45,221.28 58.55,224.52 57.5,228.3 C59.6,228.3 61.4,228.3 63.5,228.3 C62.45,224.52 61.55,221.28 60.5,217.5 C60.5,217.5 60.5,217.5 60.5,217.5 Z" stroke="#4990E2" stroke-linecap="square" fill="#4990E2"></path>
|
||||||
|
<text id="__proto__" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="70" y="239">__proto__</tspan>
|
||||||
|
</text>
|
||||||
|
<path d="M60.5,126.5 L60.5,85.5" id="Line-2" stroke="#4990E2" stroke-linecap="square" fill="#4990E2" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path id="Line-2-decoration-1" d="M60.5,85.5 C59.45,89.28 58.55,92.52 57.5,96.3 C59.6,96.3 61.4,96.3 63.5,96.3 C62.45,92.52 61.55,89.28 60.5,85.5 C60.5,85.5 60.5,85.5 60.5,85.5 Z" stroke="#4990E2" stroke-linecap="square" fill="#4990E2"></path>
|
||||||
|
<text id="__proto__-2" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="70" y="107">__proto__</tspan>
|
||||||
|
</text>
|
||||||
|
<ellipse id="Oval-1" stroke="#D0011B" sketch:type="MSShapeGroup" cx="44" cy="170" rx="42" ry="16"></ellipse>
|
||||||
|
<text id="[1,-2,-3]" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="8" y="286">[1, 2, 3]</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.9 KiB |
|
@ -0,0 +1,103 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="661px" height="399px" viewBox="0 0 661 399" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||||
|
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>native-prototypes-classes</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="native-prototypes-classes" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||||
|
<g sketch:type="MSLayerGroup" transform="translate(1.000000, 0.000000)">
|
||||||
|
<g id="Rectangle-1-+-eats:-true-+-animal" transform="translate(226.000000, 69.000000)">
|
||||||
|
<rect id="Rectangle-1" stroke="#979797" sketch:type="MSShapeGroup" x="0" y="17" width="200" height="60"></rect>
|
||||||
|
<text id="toString:-function" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="11" y="41">toString: function</tspan>
|
||||||
|
<tspan x="11" y="57">другие методы объектов</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="Object.prototype" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-style="italic" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="0" y="10">Object.prototype</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
<path d="M286.5,62.5 L286.5,21.5" id="Line-2" stroke="#4990E2" stroke-linecap="square" fill="#4990E2" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path id="Line-2-decoration-1" d="M286.5,21.5 C285.45,25.28 284.55,28.52 283.5,32.3 C285.6,32.3 287.4,32.3 289.5,32.3 C288.45,28.52 287.55,25.28 286.5,21.5 C286.5,21.5 286.5,21.5 286.5,21.5 Z" stroke="#4990E2" stroke-linecap="square" fill="#4990E2"></path>
|
||||||
|
<text id="__proto__-2" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="296" y="43">__proto__</tspan>
|
||||||
|
</text>
|
||||||
|
<path d="M286.5,195.5 L286.5,154.5" id="Line-3" stroke="#4990E2" stroke-linecap="square" fill="#4990E2" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path id="Line-3-decoration-1" d="M286.5,154.5 C285.45,158.28 284.55,161.52 283.5,165.3 C285.6,165.3 287.4,165.3 289.5,165.3 C288.45,161.52 287.55,158.28 286.5,154.5 C286.5,154.5 286.5,154.5 286.5,154.5 Z" stroke="#4990E2" stroke-linecap="square" fill="#4990E2"></path>
|
||||||
|
<text id="null" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="272" y="10">null</tspan>
|
||||||
|
</text>
|
||||||
|
<g id="Rectangle-1-+-eats:-true-+-animal-2" transform="translate(0.000000, 166.000000)">
|
||||||
|
<rect id="Rectangle-1" stroke="#979797" sketch:type="MSShapeGroup" x="0" y="51" width="200" height="60"></rect>
|
||||||
|
<text id="slice:-function" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="11" y="75">slice: function</tspan>
|
||||||
|
<tspan x="11" y="91">другие методы массивов</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="__proto__-3" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="68" y="10">__proto__</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="Array.prototype" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-style="italic" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="0" y="44">Array.prototype</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
<g id="Rectangle-1-+-eats:-true-+-animal-3" transform="translate(229.000000, 166.000000)">
|
||||||
|
<rect id="Rectangle-1" stroke="#979797" sketch:type="MSShapeGroup" x="0" y="51" width="200" height="60"></rect>
|
||||||
|
<text id="__proto__" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="67" y="10">__proto__</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="apply:-function" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="11" y="75">apply: function</tspan>
|
||||||
|
<tspan x="11" y="91">другие методы функций</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="Function.prototype" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-style="italic" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="0" y="44">Function.prototype</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
<g id="Rectangle-1-+-eats:-true-+-animal-4" transform="translate(460.000000, 166.000000)">
|
||||||
|
<rect id="Rectangle-1" stroke="#979797" sketch:type="MSShapeGroup" x="0" y="51" width="200" height="60"></rect>
|
||||||
|
<text id="toFixed:-function" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="11" y="75">toFixed: function</tspan>
|
||||||
|
<tspan x="11" y="91">другие методы чисел</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="Number.prototype" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-style="italic" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="0" y="44">Number.prototype</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="__proto__-4" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="68" y="10">__proto__</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
<path d="M129.5,187.5 L207.5,151.5" id="Line" stroke="#4990E2" stroke-linecap="square" fill="#4990E2" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path id="Line-decoration-1" d="M206.676548,151.880055 C202.80445,152.510737 199.485509,153.051323 195.613412,153.682005 C196.493434,155.58872 197.247739,157.223047 198.127761,159.129761 C201.119836,156.592364 203.684472,154.417452 206.676548,151.880055 C206.676548,151.880055 206.676548,151.880055 206.676548,151.880055 Z" stroke="#4990E2" stroke-linecap="square" fill="#4990E2"></path>
|
||||||
|
<path d="M526.5,187.5 L449.5,151.5" id="Line" stroke="#4990E2" stroke-linecap="square" fill="#4990E2" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path id="Line-decoration-1" d="M449.5,151.5 C452.479529,154.052118 455.033412,156.239647 458.012941,158.791765 C458.902353,156.889412 459.664706,155.258824 460.554118,153.356471 C456.685176,152.706706 453.368941,152.149765 449.5,151.5 C449.5,151.5 449.5,151.5 449.5,151.5 Z" stroke="#4990E2" stroke-linecap="square" fill="#4990E2"></path>
|
||||||
|
<rect id="Rectangle-5" stroke="#979797" sketch:type="MSShapeGroup" x="34" y="332" width="119" height="25"></rect>
|
||||||
|
<text id="[1,-2,-3]" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="58" y="348">[1, 2, 3]</tspan>
|
||||||
|
</text>
|
||||||
|
<rect id="Rectangle-6" stroke="#979797" sketch:type="MSShapeGroup" x="237" y="332" width="181" height="67"></rect>
|
||||||
|
<text id="function-f(args)-{" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="251" y="352">function f(args) {</tspan>
|
||||||
|
<tspan x="251" y="368"> ...</tspan>
|
||||||
|
<tspan x="251" y="384">}</tspan>
|
||||||
|
</text>
|
||||||
|
<rect id="Rectangle-7" stroke="#979797" sketch:type="MSShapeGroup" x="527" y="332" width="71" height="25"></rect>
|
||||||
|
<text id="5" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="560" y="349">5</tspan>
|
||||||
|
</text>
|
||||||
|
<path d="M286.5,325.5 L286.5,284.5" id="Line-4" stroke="#4990E2" stroke-linecap="square" fill="#4990E2" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path id="Line-4-decoration-1" d="M286.5,284.5 C285.45,288.28 284.55,291.52 283.5,295.3 C285.6,295.3 287.4,295.3 289.5,295.3 C288.45,291.52 287.55,288.28 286.5,284.5 C286.5,284.5 286.5,284.5 286.5,284.5 Z" stroke="#4990E2" stroke-linecap="square" fill="#4990E2"></path>
|
||||||
|
<text id="__proto__-5" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="296" y="306">__proto__</tspan>
|
||||||
|
</text>
|
||||||
|
<path d="M563.5,325.5 L563.5,284.5" id="Line-5" stroke="#4990E2" stroke-linecap="square" fill="#4990E2" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path id="Line-5-decoration-1" d="M563.5,284.5 C562.45,288.28 561.55,291.52 560.5,295.3 C562.6,295.3 564.4,295.3 566.5,295.3 C565.45,291.52 564.55,288.28 563.5,284.5 C563.5,284.5 563.5,284.5 563.5,284.5 Z" stroke="#4990E2" stroke-linecap="square" fill="#4990E2"></path>
|
||||||
|
<text id="__proto__-6" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="573" y="306">__proto__</tspan>
|
||||||
|
</text>
|
||||||
|
<path d="M93.5,325.5 L93.5,284.5" id="Line-6" stroke="#4990E2" stroke-linecap="square" fill="#4990E2" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path id="Line-6-decoration-1" d="M93.5,284.5 C92.45,288.28 91.55,291.52 90.5,295.3 C92.6,295.3 94.4,295.3 96.5,295.3 C95.45,291.52 94.55,288.28 93.5,284.5 C93.5,284.5 93.5,284.5 93.5,284.5 Z" stroke="#4990E2" stroke-linecap="square" fill="#4990E2"></path>
|
||||||
|
<text id="__proto__-7" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="103" y="306">__proto__</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 9.8 KiB |
|
@ -0,0 +1,40 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="200px" height="233px" viewBox="0 0 200 233" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||||
|
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>native-prototypes-object</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="native-prototypes-object" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||||
|
<g sketch:type="MSLayerGroup">
|
||||||
|
<g id="Rectangle-1-+-eats:-true-+-animal" transform="translate(0.000000, 69.000000)">
|
||||||
|
<rect id="Rectangle-1" stroke="#979797" sketch:type="MSShapeGroup" x="0" y="17" width="200" height="60"></rect>
|
||||||
|
<text id="toString:-function" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="11" y="41">toString: function</tspan>
|
||||||
|
<tspan x="11" y="57">другие методы объектов</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="Object.prototype" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-style="italic" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="0" y="10">Object.prototype</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
<g id="Rectangle-1-+-eats:-true-+-animal-2" transform="translate(0.000000, 186.000000)">
|
||||||
|
<rect id="Rectangle-1" stroke="#979797" sketch:type="MSShapeGroup" x="0" y="17" width="200" height="30"></rect>
|
||||||
|
<text id="obj" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-style="italic" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="0" y="10">obj</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
<path d="M60.5,194.5 L60.5,153.5" id="Line" stroke="#4990E2" stroke-linecap="square" fill="#4990E2" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path id="Line-decoration-1" d="M60.5,153.5 C59.45,157.28 58.55,160.52 57.5,164.3 C59.6,164.3 61.4,164.3 63.5,164.3 C62.45,160.52 61.55,157.28 60.5,153.5 C60.5,153.5 60.5,153.5 60.5,153.5 Z" stroke="#4990E2" stroke-linecap="square" fill="#4990E2"></path>
|
||||||
|
<text id="__proto__" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="70" y="175">__proto__</tspan>
|
||||||
|
</text>
|
||||||
|
<path d="M60.5,62.5 L60.5,21.5" id="Line-2" stroke="#4990E2" stroke-linecap="square" fill="#4990E2" sketch:type="MSShapeGroup"></path>
|
||||||
|
<path id="Line-2-decoration-1" d="M60.5,21.5 C59.45,25.28 58.55,28.52 57.5,32.3 C59.6,32.3 61.4,32.3 63.5,32.3 C62.45,28.52 61.55,25.28 60.5,21.5 C60.5,21.5 60.5,21.5 60.5,21.5 Z" stroke="#4990E2" stroke-linecap="square" fill="#4990E2"></path>
|
||||||
|
<text id="__proto__-2" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#4990E2">
|
||||||
|
<tspan x="70" y="43">__proto__</tspan>
|
||||||
|
</text>
|
||||||
|
<text id="null" sketch:type="MSTextLayer" font-family="Consolas" font-size="14" font-weight="normal" fill="#000000">
|
||||||
|
<tspan x="46" y="10">null</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
|
@ -5,9 +5,9 @@
|
||||||
[cut]
|
[cut]
|
||||||
## Обычный конструктор
|
## Обычный конструктор
|
||||||
|
|
||||||
Вспомним, как мы объявляли конструкторы ранее.
|
Вспомним, как мы объявляли классы ранее.
|
||||||
|
|
||||||
Например, этот код задаёт объект `Animal` без всяких прототипов:
|
Например, этот код задаёт класс `Animal` в функциональном стиле, без всяких прототипов:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//+ run
|
//+ run
|
||||||
|
@ -38,7 +38,8 @@ animal.stop(); // Зверь стоит
|
||||||
|
|
||||||
А теперь создадим аналогичный класс, используя прототипы, наподобие того, как сделаны классы `Object`, `Date` и остальные.
|
А теперь создадим аналогичный класс, используя прототипы, наподобие того, как сделаны классы `Object`, `Date` и остальные.
|
||||||
|
|
||||||
**Чтобы объявить свой класс, нужно:**
|
Чтобы объявить свой класс, нужно:
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
<li>Объявить функцию-конструктор.</li>
|
<li>Объявить функцию-конструктор.</li>
|
||||||
<li>Записать методы и свойства, нужные всем объектам класса, в `prototype`.</li>
|
<li>Записать методы и свойства, нужные всем объектам класса, в `prototype`.</li>
|
||||||
|
@ -51,6 +52,7 @@ animal.stop(); // Зверь стоит
|
||||||
// конструктор
|
// конструктор
|
||||||
function Animal(name) {
|
function Animal(name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.speed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// методы в прототипе
|
// методы в прототипе
|
||||||
|
@ -64,9 +66,6 @@ Animal.prototype.stop = function() {
|
||||||
alert(this.name + ' стоит');
|
alert(this.name + ' стоит');
|
||||||
};
|
};
|
||||||
|
|
||||||
// свойство speed со значением "по умолчанию"
|
|
||||||
Animal.prototype.speed = 0;
|
|
||||||
|
|
||||||
var animal = new Animal('Зверь');
|
var animal = new Animal('Зверь');
|
||||||
|
|
||||||
alert(animal.speed); // 0, свойство взято из прототипа
|
alert(animal.speed); // 0, свойство взято из прототипа
|
||||||
|
@ -75,23 +74,21 @@ animal.run(5); // Зверь бежит, скорость 10
|
||||||
animal.stop(); // Зверь стоит
|
animal.stop(); // Зверь стоит
|
||||||
```
|
```
|
||||||
|
|
||||||
Здесь объекту `animal` принадлежит лишь свойство `name`, а остальное находится в прототипе.
|
В объекте `animal` будут хранится свойства конкретного экземпляра: `name` и `speed`, а общие методы -- в прототипе.
|
||||||
|
|
||||||
Обратим внимание, значение `speed` по умолчанию тоже перенесено в прототип, ведь оно во всех объектах (в начале) одинаково, но вызовы `animal.run()`, `animal.stop()` в примере используют вызов `this.speed += speed`, а любая запись в `this.свойство` работает с самим объектом.
|
Совершенно такой же подход, как и для встроенных классов в JavaScript.
|
||||||
|
|
||||||
То есть, начальное значение `speed` берётся из прототипа, а новое -- пишется уже в сам объект. И в дальнейшем используется.
|
|
||||||
|
|
||||||
<img src="7.png">
|
|
||||||
|
|
||||||
## Сравнение
|
## Сравнение
|
||||||
|
|
||||||
Чем такое задание класса лучше и хуже предыдущего?
|
Чем такое задание класса лучше и хуже функционального стиля?
|
||||||
|
|
||||||
[compare]
|
[compare]
|
||||||
+Прототип позволяет хранить общие свойства и методы в единственном экземпляре, таким образом экономится память и создание объекта происходит быстрее, чем если записывать их в каждый `this`.
|
+Функциональный стиль записывает в каждый объект и свойства и методы, а прототипный -- только свойства. Поэтому прототипный стиль -- быстрее и экономнее по памяти.
|
||||||
-При объявлении класса через прототип, мы теряем возможность использовать локальные переменные и функции.
|
-При создании методов через прототип, мы теряем возможность использовать локальные переменные как приватные свойства, у них больше нет общей области видимости с конструктором.
|
||||||
[/compare]
|
[/compare]
|
||||||
|
|
||||||
|
Таким образом, прототипный стиль -- быстрее и экономнее, но немного менее удобен.
|
||||||
|
|
||||||
К примеру, есть у нас приватное свойство `name` и метод `sayHi` в функциональном стиле ООП:
|
К примеру, есть у нас приватное свойство `name` и метод `sayHi` в функциональном стиле ООП:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -128,11 +125,4 @@ var animal = new Animal("Зверь");
|
||||||
animal.sayHi(); // Зверь
|
animal.sayHi(); // Зверь
|
||||||
```
|
```
|
||||||
|
|
||||||
Ранее в каждый объект `Animal` записывалась своя функция `this.sayHi`, а теперь есть одна функция такого рода в прототипе. В сам объект мы пишем только то, что свойственно именно этому объекту.
|
Впрочем, недостаток этот -- довольно условный. Ведь при наследовании в функциональном стиле также пришлось бы писать `this._name`, чтобы потомок получил доступ к этому значению.
|
||||||
|
|
||||||
## Задачи
|
|
||||||
|
|
||||||
Обычно свойства по умолчанию хранятся в прототипе. Но если свойство по умолчанию -- объект, то его в прототипе хранить нельзя.
|
|
||||||
|
|
||||||
Почему? Смотрите задачу ниже на эту тему.
|
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 56 KiB |
|
@ -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
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<img src="8.png">
|
|
||||||
|
|
||||||
Так что объект `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`. Но почему?
|
|
||||||
|
|
||||||
Вот иллюстрация, которая наглядно демонстрирует причину:
|
|
||||||
|
|
||||||
<img src="9.png">
|
|
||||||
|
|
||||||
То есть, свойство `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` на новый объект. И ничего страшного в этом нет.
|
|
||||||
|
|
||||||
Но если мы хотим использовать это свойство сами, чтобы при необходимости получать функцию-конструктор объекта, но при смене прототипа нужно самим смотреть, чтобы ненароком не перезаписать его.
|
|
||||||
|
|
||||||
|
|