# 03. Function Invocation

> From [Gentle explanation of 'this' keyword in JavaScript](https://rainsoft.io/gentle-explanation-of-this-in-javascript/)

In JavaScript, `this` is the current execution context of a function. JS has 5 function invocation types:

* **Function invocation**: `alert('Hello World!')`
* **Method invocation**: `console.log('Hello World!')`
* **Arrow function invocation**.
* **Constructor invocation**: `new RegExp('\\d')`
*   **Indirect invocation**: `alert.call(undefined, 'Hello World!')`

    and each one defines its own context, this behaves slight different than developer expects.

Before starting, let's familiarize with a couple of terms:

* **Invocation** is executing the code that makes the body of a function (simply calling the function). For example `parseInt` function invocation is `parseInt('15')`.
* **Context** of an invocation is the value of `this` within function body.
* **Scope** of a function is a set of variables, objects, functions accessible within a function body.

## Function Invocation

In function invocation `this` is the _global object_. The global object is determined by the execution environment.

* It is the `window` object in a web browser.
* It is the `global` object in a node environment.
* `this` is `undefined` in a function invocation in strict mode. The strict mode is active not only in the current scope, but also in the inner scopes (for all functions declared inside).

```javascript
function func() {
  return this;
}

const val = func();
val === this; // true

// in browser
val === window; // true

// in node
val === global; // true
```

A common trap with the function invocation is thinking that this is the same in an inner function as in the outer function. Correctly the context of the inner function depends only on invocation, but not on the outer function's context. To have the expected `this`, modify the inner function's context with indirect invocation (using `.call()` or `.apply()`) or create a bound function (using `.bind()`).

> this для вложенной функции определяется самой этой функцией, только если она не стрелочная.

## Method Invocation

Method invocation is performed when in a form of property accessor that evaluates to a function object. `this` is the _object that owns the method_ in a method invocation.

```javascript
const calc = {
  num: 0,
  increment() {
    console.log(this === calc); // => true
    this.num += 1;
    return this.num;
  }
};
// method invocation. this is calc
calc.increment(); // => 1
calc.increment(); // => 2
```

A method from an object can be extracted into a separated variable. When calling the method using this variable, you might think that this is the object on which the method was defined. Correctly if the method is called without an object, then a function invocation happens: where this is the global object `window` or `undefined` in strict mode. Creating a bound function (using `.bind()`) fixes the context, making it the object that owns the method.

## Arrow function Invocation

Arrow-функции не имеют собственного `this` и оно для их определяется по правилам лексической области видимости. Простыми словами, Arrow функции заимствуют `this` из окружающей их области видимости.

## Constructor Invocation

Constructor invocation is performed when `new` keyword is followed by an expression that evaluates to a function object. When a property accessor `myObject.myFunction` is preceded by `new` keyword, JavaScript will execute a constructor invocation, but not a method invocation.

In a constructor invocation `this` is the newly created object:

```javascript
function Country(name, traveled) {
  this.name = name ? name : "United Kingdom";
  this.traveled = Boolean(traveled); // transform to a boolean
}
Country.prototype.travel = function() {
  this.traveled = true;
};
// Constructor invocation
const france = new Country("France", false);
// Constructor invocation
const unitedKingdom = new Country();

france.travel(); // Travel to France
```

Using a function invocation to create objects is a potential problem (excluding factory pattern), because some constructors may omit the logic to initialize the object when `new` keyword is missing.

```javascript
function Vehicle(type, wheelsCount) {
  this.type = type;
  this.wheelsCount = wheelsCount;
  return this;
}
// Function invocation
const car = Vehicle("Car", 4);
car.type; // => 'Car'
car.wheelsCount; // => 4
car === window; // => true
```

## Indirect Invocation

Indirect invocation is performed when a function is called using `.call()` or `.apply()` methods. `this` is the first argument of `.call()` or `.apply()` in an indirect invocation

* The method `.call(thisArg, arg1, arg2, ...)` accepts the first argument `thisArg` as the context of the invocation and a list of arguments `arg1, arg2, ...` that are passed as arguments to the called function.
* The method `.apply(thisArg, [arg1, arg2, ...])` accepts the first argument `thisArg` as the context of the invocation and an array-like object of values `[arg1, arg2, ...]` that are passed as arguments to the called function.

```javascript
function increment(number) {
  return ++number;
}
increment.call(undefined, 10); // => 11
increment.apply(undefined, [10]); // => 11
```

> The spread operator (`...`) mostly replaces `apply()`.

## `this` propagation

Существует проблема, когда функция-callback, вызванная внутри другой функции имеет свой собственный `this`, который равен или глобальному объекту, или `undefined` (в строгом режиме).

В следующем примере `this.name` внутри функции выдаст ошибку, поскольку внутри анонимной функции `this = undefined`.

```javascript
const obj = {
    name: 'Jane',
    friends: [ 'Tarzan', 'Cheeta' ],
    loop() {
        ￼'use strict';
        this.friends.forEach(function (friend) { // (1)
            console.log(this.name + ' knows ' + friend); // (2)
        });
    }
};
```

Существует четыре способа решения этой проблемы:

1. Введение дополнительной временной переменной:

```javascript
loop() {
    'use strict';
    const self = this;
    this.friends.forEach(function (friend) {
        console.log(self.name + ' knows ' + friend);
    });
}
```

1. Использование `bind` для явного задания `this`:

```javascript
loop() {
    'use strict';
    this.friends.forEach(function (friend) {
        console.log(this.name + ' knows ' + friend);
    }.bind(this));
}
```

1. Передача `this` параметра в функцию `forEach`:

```javascript
loop() {
    'use strict';
    this.friends.forEach(function (friend) {
        console.log(this.name + ' knows ' + friend);
    }, this);
}
```

1. Использование arrow-functions в качестве функции обратного вызова (рекомендуемый):

```javascript
loop() {
    'use strict';
    this.friends.forEach((friend) => {
        console.log(this.name + ' knows ' + friend);
    });
}
```

## Activation Object

При вызове функции создается объект активации, остающийся для вас невидимым. Это скрытая структура данных, которая содержит информацию и связывает все то, что функция должна выполнить, а также содержит обратный адрес активации вызывающей функции.

В языках, подобных C, объекты активации размещаются в стеке. Они покидают стек (или выводятся из него), когда функция возвращает управление. В JavaScript происходит иначе. Объекты активации JavaScript размещает в куче, как обычные объекты. При возвращении функцией управления объекты активации не проходят автоматическую деактивацию. Вместо этого объект активации может выживать, пока на него есть ссылка. Объекты активации подпадают под сборку мусора, как и обычные объекты.

В объекте активации содержатся:

* ссылка на функциональный объект;
* ссылка на объект активации вызывающей функции. Она используется инструкцией `return` для возврата управления;
* информация о возвращении, которая применяется для продолжения вы- полнения кода после вызова. Обычно это адрес инструкции, выполняемой сразу же после вызова функции;
* параметры функции, инициализированные аргументами;
* переменные функции, инициализированные значением `undefined`;
* временные переменные, используемые функциями для вычисления сложных выражений;
* содержимое `this`, которое может быть ссылкой на интересующий объект, если функциональный объект был вызван как метод.

В функциональном объекте содержатся также два скрытых свойства:

* ссылка на исполняемый код функции;
* ссылка на объект активации, который был активен в момент создания функ- ционального объекта. Это делает возможным создание замыкания. Функция может использовать это скрытое свойство для доступа к переменным той функции, которая ее создала.
