Первый пример ниже. Мы потеряли контекст выполнения, когда присвоили метод переменной. На выходе наш кот назван undefined вместо желаемого Тито. Как сохранить желаемый контекст выполнения?

let animal = {
  cat: {
    name: 'Tito',
    meow: function() {
      console.log(`my name is ${this.name} and I'm meowing. Meow!`);
    }
  }
}
let ourMeowFunc = animal.cat.meow;
ourMeowFunc();

Решение: мы можем создать внешнюю функцию для передачи нашей переменной.

function callFunction(func, context) {
  func.call(context);
}
let animal = {
  cat: {
    name: 'Tito',
    meow: function() {
    console.log(`my name is ${this.name} and I'm meowing. Meow!`);
    }
  }
}
let ourMeowFunc = animal.cat.meow;
callFunction(ourMeowFunc, animal.cat);

Однако нам необходимо предоставить контекст выполнения, чтобы он не вызывался просто как функция, и вызывать функцию в callFunction с помощью .call () вместо обычной функции. . Нам нужно указать, что контекст выполнения - это объект, на который ссылается свойство cat объекта animal.

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

function callFunction(func, context) {
  func.call(context);
}
let animal = {
  cat: {
    name: 'Tito',
    meow: function() {
    console.log(`my name is ${this.name} and I'm meowing. Meow!`);
    }
  }
}
let ourMeowFunc = animal.cat.meow.bind(animal.cat);
callFunction(ourMeowFunc, animal.cat);

Иногда мы хотим выполнить функцию внутри метода:

let athlete = {
  name: 'Joe',
  run: function() {
    function running() {
      console.log(`${this.name} is running`);
    }
    running();
  }
}
athlete.run();

Это выводит undefined вместо желаемого свойства name, потому что running () вызывается как обычная функция в методе run, поэтому контекст выполнения является глобальным объектом.

Мы можем использовать другое решение: создать локальную переменную в определении функции run и присвоить ее this:

let athlete = {
  name: 'Joe',
  run: function() {
    let self = this;
    function running() {
      console.log(`${self.name} is running`);
    }
    running();
  }
}
athlete.run();

Причина, по которой это работает, заключается в том, что running () имеет доступ к локальной переменной self, которая содержит значение this. Значение this, удерживаемое self, является объектом спортсмен.

Другой пример этого ниже:

let obj = {
  type: 'round'
}
function goRound() {
  let self = obj;
  function going() {
    console.log(self.type);
  }
  going();
}
goRound();

Мы также можем использовать .call () для предоставления явного контекста выполнения:

let obj = {
  type: 'round'
}
function goRound() {
  function going() {
    console.log(this.type);
  }
  going.call(obj);
}
goRound();

У нас также есть возможность использовать .bind (), и мы можем выполнить переменную, которой мы назначаем функцию, как обычную функцию, потому что контекст выполнения устанавливается постоянно:

let obj = {
  type: 'round'
}
function goRound() {
  function going() {
    console.log(this.type);
  }
  let endFunc = going.bind(obj);
  endFunc()
}
goRound();

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

Наконец, стрелочная функция - это простой и часто используемый способ сохранить контекст выполнения:

let obj = {
  type: 'round',
  goRound: function () {
    let going = () => {
      console.log(this.type);
    }
    going();
  }
}
obj.goRound();

Стрелочные функции наследуют свой контекст выполнения из окружающей области. В этом случае при определении значения this имеет значение, где определена функция.