Доступ к переменной родительской функции из функции обратного вызова и встроенной функции

Я полагал, что на первый взгляд обе функции, вызывающие саму себя, одинаковы, единственное различие между ними заключается в том, что в первой я передаю функцию обратного вызова, а затем выполняю объект аргументов, а во вторую выполняю одну и ту же вещь, вызывая функцию самопризывания. Теперь перейдем к точкам доступа к родительской переменной в первом примере с именем "undefined"в то время как во втором примере это доступно и дает вывод"Nishant"Я не могу понять, как это работает!!

(function(){
    var name = "Nishant";
    arguments[0]();

})(function(){console.log(name);});

Вывод: (пустая строка)

(function(){
  var name = "Nishant";
  (function(){console.log(name);})()
})();

Выход: нишант

2 ответа

Я не могу понять, как это работает!

У JavaScript есть лексическая область. Это означает, что область действия определяется тем, где функции определены внутри исходного кода (в отличие от динамической области действия, где область определяется при вызове функций во время выполнения).

Давайте добавим некоторые имена к вашим функциям, чтобы мы могли легче ссылаться на них:

(function foo(){
    var name = "Nishant";
    arguments[0]();
})(function bar(){console.log(name);});

В этом случае bar определяется за пределами foo и, следовательно, не может иметь доступ к переменной, определенной внутри foo, На самом деле, на данный момент bar создана переменная name внутри foo даже не существует, так как foo еще не был выполнен
Может быть, это легче увидеть, если вы не включите определение:

function bar(){console.log(name);}

(function foo(){
    var name = "Nishant";
    arguments[0]();
})(bar);

Это может выглядеть более знакомым, и я уверен, что вы не ожидаете, что name внутри bar имеет какое-либо отношение к name внутри foo, право?


В другом случае

(function foo(){
  var name = "Nishant";
  (function bar(){console.log(name);})()
})();

вы определили bar внутри foo, name также внутри foo и поэтому bar имеет доступ к этой переменной (лексическая область + закрытие).

"имя" в первой версии относится к глобальному window.name свойство *, а во втором примере к закрытому имени переменной через замыкание. window.name свойство является необязательным и по умолчанию имеет пустую строку.

Если это свойство не существует, ваш первый пример выдаст ошибку ссылки.

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

window.name = "NoClosure";
(function(){
    var name = "Closure";
    arguments[0](); 
})(function(){console.log(name);}); //>"NoClosure"

window.name = "NoClosure";
(function(){
    var name = "Closure";
    (function(){console.log(name);})(); //>"Closure"
})();

Если вы проверяете обратного вызова с console.dir()Вы можете видеть, что у него нет замыкания, вот фрагмент, если вы хотите проверить это самостоятельно.

(function wrapper(){
    var isPrivate = "A closure could see me";
    console.dir(arguments[0]);
})(function callback(){});

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

(function outerScope(){
   var outerVar = "in outer scope";
   (function innerScope(cb){
       var innerVar = "in inner scope";
       cb();
   })(function callback(){
       console.log(
          "outer:"+ typeof outerVar,
          "inner:"+ typeof innerVar);
       console.dir(arguments.callee);
   })
})()

* источник https://developer.mozilla.org/en-US/docs/Web/API/Window.name

Другие вопросы по тегам