renovations

This commit is contained in:
Ilya Kantor 2015-01-14 10:23:45 +03:00
parent c7d4c7e3ff
commit e1948130f6
170 changed files with 1496 additions and 1161 deletions

View file

@ -96,9 +96,9 @@ user = null;
admin.sayHi(); // упс! внутри sayHi обращение по старому имени, ошибка!
```
**Использование `this` гарантирует, что функция работает именно с тем объектом, в контексте которого вызвана!**
Использование `this` гарантирует, что функция работает именно с тем объектом, в контексте которого вызвана.
Через `this` метод может обратиться к любому свойству объекта, а, при желании, и передать объект куда-либо:
Через `this` метод может не только обратиться к любому свойству объекта, но и передать куда-то ссылку на сам объект целиком:
```js
//+ run
@ -112,8 +112,8 @@ var user = {
*/!*
};
function showName(obj) {
alert( obj.name );
function showName(namedObj) {
alert( namedObj.name );
}
user.sayHi(); // Василий
@ -157,7 +157,7 @@ admin['g'](); // Админ (не важно, доступ к объекту ч
*/!*
```
**Значение `this` не зависит от того, как функция была создана, оно определяется исключительно в момент вызова.**
Итак, значение `this` не зависит от того, как функция была создана, оно определяется исключительно в момент вызова.
## Значение this при вызове без контекста
@ -176,7 +176,9 @@ function func() {
func();
```
В современном стандарте языка это поведение изменено, вместо глобального объекта `this` будет `undefined`.
Таково поведение в старом стандарте.
А в режиме `use strict` вместо глобального объекта `this` будет `undefined`:
```js
//+ run
@ -188,12 +190,13 @@ function func() {
func();
```
Это стоит иметь в виду для общего развития, но обычно если в функции используется `this`, то она, всё же, проектируется для вызова в контексте объекта.
Обычно если в функции используется `this`, то она, всё же, служит для вызова в контексте объекта, так что такая ситуация -- скорее исключение.
[warn header="`this` теряется при операциях с методом"]
Ещё раз обратим внимание: контекст `this` никак не привязан к функции, даже если она создана в объявлении объекта.
## Ссылочный тип
Чтобы `this` передался правильно, нужно вызвать функцию именно через точку (или квадратные скобки). Любой более хитрый вызов приведёт к потере контекста, например:
Контекст `this` никак не привязан к функции, даже если она создана в объявлении объекта. Чтобы `this` передался, нужно вызвать функцию именно через точку (или квадратные скобки).
Любой более хитрый вызов приведёт к потере контекста, например:
```js
//+ run
@ -204,25 +207,38 @@ var user = {
};
user.hi(); // Вася (простой вызов работает)
*!*
// а теперь вызовем user.hi или user.bye в зависимости от имени
(user.name == "Вася" ? user.hi : user.bye)(); // undefined
*/!*
```
В последней строке примера метод получен в результате выполнения тернарного оператора и тут же вызван. При этом `this` теряется.
В последней строке примера метод получен в результате выполнения тернарного оператора и тут же вызван. Но `this` при этом теряется.
Иначе говоря, такой вызов эквивалентен двум строкам:
Если хочется понять, почему, то причина кроется в деталях работы вызова `obj.method()`.
```js
var method = (user.name == "Вася" ? user.hi : user.bye);
method(); // без this
```
Он ведь, на самом деле, состоит из двух независимых операций: точка `.` -- получение свойства и скобки `()` -- его вызов (предполагается, что это функция).
[/warn]
## Задачи
Функция, как мы говорили раньше, сама по себе не запоминает контекст. Чтобы "донести его" до скобок, JavaScript применяет "финт ушами" -- точка возвращает не функцию, а значение специального "ссылочного" типа [Reference Type](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-reference-specification-type).
Этот тип представляет собой связку "base-name-strict", где:
<ul>
<li>*base* -- как раз объект,</li>
<li>*name* -- имя свойства,</li>
<li>*strict* -- вспомогательный флаг для передачи `use strict`.</li>
</ul>
То есть, ссылочный тип (Reference Type) -- это своеобразное "три-в-одном". Он существует исключительно для целей спецификации, мы его не видим, поскольку любой оператор тут же от него избавляется:
<ul>
<li>Скобки `()` получают из `base` значение свойства `name` и вызывают в контексте base.</li>
<li>Другие операторы получают из `base` значение свойства `name` и используют, а остальные компоненты игнорируют.</li>
</ul>
Поэтому любая операция над результатом операции получения свойства, кроме вызова, приводит к потере контекста.
Аналогично работает и получение свойства через квадратные скобки `obj[method]`.