Главная » Контекст вызова. This

Контекст вызова. This


12.06.2021, 20:28
Контекст вызова функции - это то, что её окружает и в каких условиях она вызывается.

Функцию можно вызвать несколькими способами, при этом у каждого способа контекст вызова будет различаться.

Стандартный вызов функции

Код

function showThis() {
  console.log(this);
}
showThis();

В нестрогом режиме в консоли мы получим Window
В строгом режиме получим undefined

Если внутри функции используется другая функция, то и её контекст вызова будет также либо Window, либо undefined, в зависимости от режима

Вызов функции как метода объекта

Код

const obj = {
  a: 20,
  b: 15,
  sum: function() {
  console.log(this);
  }
};
obj.sum();

В консоли мы увидим объект, в котором находится этот метод (эта функция):

{a: 20, b: 15, sum: ƒ}

У метода (функции) внутри объекта контекст вызова будет ссылаться на этот объект.

Если же внутри метода объекта будет вызываться другая функция, то её контекст вызова уже будет как при обычном вызове функции, потому что эта функция уже не является методом объекта.

Контекст вызова внутри функции-конструктора

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

В примере ниже имеем переменную ivan, в которой созданный путём вызова функции-конструктора новый объект, так вот this ссылается именно на него.

Код

function User(name, id) {
  this.name = name;
  this.id = id;
  this.human = true;
}
let ivan = new User('Ivan', 23);

Таким образом, когда мы с помощью new вызываем функцию-конструктор, создаётся новый объект, в который с помощью this.name, this.id и так далее мы передаём новые свойства и методы.

This в конструкторах и классах - это новый экземпляр объекта

Ручное присваивание this функции

Код

function sayName() {
  console.log(this); /* => Window либо undefined */
  console.log(this.name);
}
const user = {
  name: 'John'
};

В данном случае this будет либо Window, либо undefined (в зависимости от режима, в котором написан код)

Как сделать, чтобы this ссылался на user? (чтобы получить доступ к name)

Для этого используются методы call() и apply(), делается так:

Код

sayName.call(user); /* { name: 'John' } John */
sayName.apply(user); /* { name: 'John' } John */

В консоли получаем объект, к которому привязались, функция благодаря этим методам приобретает свой контекст.

Отличие методов call() и apply() в принципе передачи аргументов:

для call() агументы передаются в виде строки через запятую:

Код

sayName.call(user, 'Smith');

для apply() в виде массива:

Код

sayName.apply(user, ['Smith']);

Ещё одним методом ручного присвоения контекста является метод bind(), создающий новую функцию, связанную с определённым контекстом.

Например, функция:

Код

function count(num) {
  return this * num;
}

Здесь не хватает какого-то контекста вызова, который бы умножался на число, передаваемое в num при вызове этой функции.

Создадим новую переменную и поместим в неё новую функцию с помощью bind():

Код

const double = count.bind(2);

Теперь double - это новая функция с жёстко привязанным контекстом (это 2) и эта цифра 2 в качестве контекста this уже передаётся за счёт bind() в функцию count

Код

console.log(double(3)); /* => 6 */
console.log(double(13)); /* => 26 */

Работа с контекстом. Обработчики событий

Получим кнопку со страницы и добавим обработчик события:

Код

const btn = document.querySelector('button');

btn.addEventListener('click', function() {
  console.log(this);
}

В консоли получаем:

Код
<button>...</button>

В случае, если функция записана в классическом (не стрелочном) виде, контекстом вызова функции в обработчике события будет элемент, на котором произошло событие.
По сути, здесь this = event.target

Поэтому мы можем смело написать такой код и он отлично отработает:

Код

btn.addEventListener('click', function() {
  this.style.backgroundColor = 'red'; /* цвет кнопки изменится на красный */
});

Стрелочные функции и контекст вызова

У стрелочной функции нет своего контекста вызова, контекст вызова она всегда берёт у своего родителя.

Код

const obj = {
  num: 5,
  sayNumber: function() {
  const say = () => {
  console.log(this);
  };
  say();
  }
};

obj.sayNumber();

В данном случае родителем стрелочной функции say является метод sayNumber(), у которого контекст ссылается на объект obj.

Таким образом, this в стрелочной функции ссылается на этот же объект obj (контекст родителя) и в консоли мы увидим этот объект

Ещё немного о стрелочных функциях

Использование стрелочных функций позволяет сокращать код, например:

Код

const double = (a) => {
  return a * 2;
};

Если тело функции помещается в одну строку, то код выше можно сократить:

Код

const double = (a) => a * 2; /* при этом return можно не писать */

Если же у стрелочной функции всего один аргумент, можно опустить круглые скобки:

Код

const double = a => a * 2;

Если стрелочная функция используется в обработчике события, контекст вызова теряется и будет равен undefined.

Поэтому в таких случаях используется event:

Код

btn.addEventListener('click', (e) => {
  e.target.style.backgroundColor = 'red'; /* кнопка поменяет цвет на красный */
});

КОММЕНТАРИИ (0)