Возвращаемые функции в javascript, понимание области и закрытия

Я смотрел сайт разработчика Mozillas при закрытии javascript, и у них был этот пример кода.

  function makeAdder(x){
    return function (y) {
        console.log(y + " this is y")
        console.log(x + " this is x")
        return x + y;
        }
}
var add10 = makeAdder(10);
console.log(add10(2)); // 12

Теперь я понимаю, что атрибут X установлен, но я не понимаю, как влияет область действия y. Я знаю, что это функция возврата, но мой мозг стал мхать, пытаясь представить себе, как вы могли бы установить y, когда не было ссылок на него. может кто-нибудь объяснить?

Ответ 1

makeAdder возвращает функцию, с которой вы можете передать параметр y. Он устанавливается во время вызова, в отличие от x, который устанавливается во время создания новой функции (во время вызова makeAdder).

В случае этого примера вывод эквивалентен написанию:

function add10(y) {
    return 10 + y;
}

console.log(add10(2)); // 12

Ничего нового здесь не происходит. Пример кода в основном пытается проиллюстрировать, что для x создается замыкание.

Итак, makeAdder, здесь, точно названо: когда вы передаете ему 10, он дает вам функцию, которая добавит 10 ко всему, что вы передадите этой новой функции.

var add10 = makeAdder(10);
var add20 = makeAdder(20);

console.log(add10(1) + add20(1)); // 32

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

Сценарий реального мира может быть примерно таким:

var buttons = document.getElementsByClassName('myButton');
for(var i = 0; i < buttons.length; i++) {
    buttons[i].onclick = function() {
        alert('You clicked button ' + i);
    };
}

В приведенном выше коде i будет повторяться по всему набору до нажатия любой из кнопок. Поэтому все кнопки будут уведомлять обо всех buttons.length. Вместо этого вы можете сделать следующее:

var makeAlert = function(x) {
    return function() {
        alert('You clicked button ' + x);
    };
};

for(var i = 0; i < buttons.length; i++) {
    buttons[i].onclick = makeAlert(i);
}

Разница в том, что i не используется, когда кнопка нажата (которая будет после всей итерации), но она используется во время итерации, в то время, когда i будет имеют различное значение для каждой кнопки.

Вместо создания переменной makeAlert вы часто увидите, что этот тип кода записывается как анонимная функция, вызывается немедленно. Код ниже по существу эквивалентен приведенному выше коду:

for(var i = 0; i < buttons.length; i++) {
    buttons[i].onclick = (function(x) {
        return function() {
            alert('You clicked button ' + x);
        };
    })(i);
}

Ответ 2

То, что вы просите, это функция, которая что-то делает для вас:

  function giveMeAFunctionThatBeeps(){
    return function () {
         alert('Beep!');
        }
}

var beeper = giveMeAFunctionThatBeeps();

beeper(); // beeps!

Фактическая функция getMeAFunctionThatbeeps - это просто factory, которая дает вам функцию, которая делает то, что вы хотите.

В примере, который они предоставили, вы делаете то же самое, что и beeper, но вы также передаете значение:

  function giveMeAFunctionThatBeepsANumber(x){
    return function () {
         alert('Beep ' + x);
        }
}

Это возвращает beeper (это a factory запомнить), но beeper предупреждает о значении x.

Однако это значение устанавливается при первом создании звукового сигнала:

var beeper = giveMeAFunctionThatBeeps(5);

beeper(); // beeps 5!

Теперь звуковой сигнал застрял в звуковом сигнале 5, и мы ничего не можем с этим поделать.

Следующий пример: если вы хотите создать звуковой сигнал, который подает звуковой сигнал любому номеру:

  function giveMeAFunctionThatBeepsANumber(){
    return function (x) {
         alert('Beep ' + x);
        }
}

var beeper = giveMeAFunctionThatBeeps();

beeper(6); // beeps 6!
beeper(7); // beeps 7!

Как теперь мы просим factory дать нам функцию, мы можем подключить число.

Затем, наконец, исходный пример - оба из приведенных выше:

  function giveMeAFunctionThatBeepsANumber(x){
    return function (y) {
         alert('Beep ' + (x + y));
        }
}

var beeper = giveMeAFunctionThatBeeps(2);

Когда мы создаем звуковой сигнал, мы проходим 2. Помните, как это было выше, мы не можем изменить это позже! Он всегда будет звучать 2...

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

beeper(6); // beeps 8! because x was set when we created it, and y is what we pass in.

Ответ 3

Функции можно рассматривать как специальные объекты, которые содержат исполняемый код, а также свойства. Каждая функция имеет специальное свойство [scope], которое представляет среду, в которой она была, когда она была определена. Если функция возвращается из другой функции, эта ссылка на старую среду закрывается новой функцией в "закрытии".

поэтому, когда вы вызываете var add10 = makeAdder(10), происходит то, что возвращаемая функция x имеет значение 10, которое привязано к ней, а вызов console.log(add10(2)) печатает 12.

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

Ответ 4

Функция makeAdder возвращает функцию при ее вызове. Эта функция, возвращаемая makeAdder, принимает один параметр; который называется y.

Переменная y существует только во время вызова функции, возвращаемой makeAdder. Он создается каждый раз, когда он вызывается и уничтожается при возврате функции.

С другой стороны, переменная x создается при вызове makeAdder и сохраняется из-за закрытия, созданного функцией makeAdder. Он будет уничтожен, если больше не будет ссылок на возвращаемую функцию.

Ответ 5

Итак, add10 = makeAdder(10); действительно возвращает эту функцию:

function(y) {
  console.log(y + " this is y")
  console.log("10" + " this is x")
  return 10 + y;
}

Тогда add10(2) вызывает эту функцию, заменяя y на 2 всюду:

  console.log("2" + " this is y")
  console.log("10" + " this is x")
  return 10 + 2;