Функция, определенная в setTimeout, имеет доступ к внешним переменным в JavaScript

#javascript #scope #this #settimeout

#javascript #область видимости #это #время установки

Вопрос:

Я знаю, что this ключевое слово всегда ссылается на this текущую область, которая меняется каждый раз, когда вы что-то function() { ... } вводите. Мой вопрос в том, почему у меня есть доступ к переменной внешней области x видимости в функции внутри setTimeout функции?

 var x = 45;

function getRecipe(recipe) {
  x = 35;
  return {
    displayRecipe: function(a) {
      //here we have access to x=35
      setTimeout(function() {
        //why do we have access to x=35 and to recipe here?
        console.log(this.x   a   recipe);
      }, 1500)
    }
  }
}

getRecipe("noodles").displayRecipe(2); 

Ответ №1:

Когда не в строгом режиме и когда this вызов не установлен, this внутренние функции по умолчанию будут иметь значение глобального объекта ( window в браузерах).

 function f1() {
  return this;
}

console.log(f1() === window); // true 

Также в браузерах, когда они не находятся в строгом режиме, глобальные переменные (переменные, объявленные в глобальной области видимости), объявленные с var помощью, также создаются как члены глобального объекта.

 var foo = "foobar";
console.log(foo === window.foo); 

Поскольку ваша x объявлена как глобальная переменная, она также добавляется как член window объекта. Поскольку ваш setTimeout обратный вызов явно не устанавливает область this видимости, он также по умолчанию использует глобальный объект, и поэтому возможно, что вы можете получить доступ x через this .

Если x бы она не была объявлена в глобальной области видимости (или была бы объявлена в строгом режиме или с let const помощью оператора / ), вы не смогли бы получить к ней доступ:

 (function() {
  var x = 45;

  function getRecipe(recipe) {
    x = 35;
    return {
      displayRecipe: function(a) {
        //here we have access to x=35
        setTimeout(function() {
          //why do we have access to x=35 and to recipe here?
          console.log(this.x, a, recipe);
        }, 1500)
      }
    }

  }

  getRecipe("noodles").displayRecipe(2);
})(); 

Комментарии:

1. итак, x = 35 объявлено в глобальной области видимости?

2. var x = 45; объявлена в глобальной области видимости и, следовательно, является глобальной переменной. Вы меняете значение этой глобальной переменной на 35 значение внутри вашей getRecipe функции. (Но изменение значения не изменяет область действия переменной.)

Ответ №2:

Вы должны поставить let перед x=35

 var x=45;
function getRecipe(recipe){
      let x=35;
      return{
         displayRecipe: function(a){
         //here we have access to x=35
            setTimeout(function(){
                //why do we have access to x=35 and to recipe here?
                console.log(this.x   a   recipe );
            },1500)
         }
      }

}

getRecipe("noodles").displayRecipe(2);