Первый пример ниже. Мы потеряли контекст выполнения, когда присвоили метод переменной. На выходе наш кот назван 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 имеет значение, где определена функция.