Вложенные функции, замыкания и область действия

Я пытался обернуть голову вокруг прицела, особенно закрытия. Я знаю, что есть много постов на эту тему, и я много читаю. Но большинство мест называют эту тему продвинутой и используют терминологию, которую довольно трудно понять. Мне бы хотелось быть абсолютно уверенным, что я правильно понял основы, чтобы не углубляться в более сложные темы с неправильным представлением о том, как на самом деле работают функции.

Итак... Я выбрал основную функцию и очень хотел бы, чтобы кто-то сказал мне, действительно ли то, что я думаю, происходит под капотом.

Это код:

function sum(a) {


  return function(b) {  
    return a+b
  }
}

console.log( sum(1)(sum(2)))

(Я знаю, что на самом деле это не сумма, я был настроен, чтобы попытаться понять, что происходит на каждом этапе.)

Итак, мое главное сомнение было в том, почему А было 1, а не 2. Я пришел к выводу, что замыкание создается, как только function(b)создан, чтобы принять sum(2) в качестве аргумента, сразу после возвращения sum(1), Поэтому, согласно определению замыкания, я предполагаю, что во время создания функции она также сохраняет лексическую среду (в которой a = 1). Это правильно?

Я сделал схему шагов.

схема

3 ответа

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

Теперь мы подошли к тому, что, по-видимому, вас смущает: внутренняя функция получает только копию объема суммы, а не ссылку на исходную. Это означает, что если мы вернемся из sum и, таким образом, исключить его область, эта копия остается неизменной (a внутренней функции остается 1). Дальнейшие вызовы функций sum с другими аргументами также не влияют на закрытие.

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

Технически говоря a из sum хранится в стеке, тогда как захваченный a закрытия хранится в куче и, таким образом, не зависит от времени жизни sum,

Кстати, то, что вы здесь делаете, называется карри. Вместо звонка sum с несколькими аргументами вы вызываете это процедурно, с одним аргументом на вызов:

sum(1, 2); // multi argument form
sum(1)(2); // curry form

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

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

function greeting(name) {
  var salute = "Hello "; // This is a closure

  return function() {
    console.log(salute + name);
  }
}

var greet = greeting("Dave");

greet();    // Hello Dave

Вы можете узнать больше о замыканиях в серии книг Кайла Симпсона " Вы не знаете JS", но для этой конкретной темы отметьте " Вы не знаете JS: Область применения и замыкания". Он использует простой и точный язык для объяснения таких сложных понятий, как этот.

Вот что происходит

1) Если функция возвращает функцию и эта возвращаемая функция вызывается немедленно, она вызывается currying (Функциональный термин программирования). Вы смешали currying а также closure обе концепции в этом примере.

2) Сначала твой sum(1) часть называется. который вернется function(b) {return a+b} (давайте отнесем это как #1), но с помощью он будет оставаться в живых a как 1 для только для контекста #1.

3) Поскольку аргумент функции является самим вызовом функции, эта часть аргумента будет вызвана. например sum(1)(sum(2)), Вот sum(2) часть будет вызвана и возвращается function(b) {return a+b} (давайте назовем это # ​​2), также это будет поддерживать a как 2 для контекста только #2 (закрытие).

4) Теперь мы немедленно вызываем #1st с #2nd в качестве параметра с этим синтаксисом каррирования - #1st (#2nd)

5) так наш a является нераспределенной переменной и имеет значение 1, b переменная имеет значение function(b) {return a+b}, Поскольку мы объединяем эти два, итоговый результат 1function(b) {return a+b}

NB - a) Если вы хотите получить сумму a+b, а не странный результат, просто измените вашу последнюю строку как console.log(sum(1)(2)), б) Если вы заметили закрытие a значение 2 в функции, обозначенной #2nd, никогда не используется нигде, кроме как живым.

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