Пример закрытия JavaScript и объяснение

Я нашел этот пример закрытия в codeproject, но он не объясняет, как это работает.

    function getMultiplier(multiplyBy){
       function multiply(num){
          return multiplyBy * num;
       }
 
       return multiply;
    }
 
    var multiplyByTwo = getMultiplier(2);
    var multiplyByTen = getMultiplier(10);
    var twoIntoFive = multiplyByTwo(5); 
    var tenIntoSix = multiplyByTen(6);  

    console.log(twoIntoFive); // 10
    console.log(tenIntoSix); // 60

Теперь я собираюсь предположить, что происходит с моим мозгом C. Пожалуйста, поправьте меня или дайте свое объяснение.

  1. функции в javascript также могут быть объектами, поэтому внутренняя функцияmultiplier(num) является методом getMultiplier, смотрящим снаружи.
  2. varmultiplierByTwo присваивается возвращаемое значение функции getMultiplier при вызове с аргументом 2.
  3. когда вы вызываете getMultiplier(2), интерпретатор javascript создает объект в памяти на основе определения getMultiplier().
  4. этот объект имеет метод, умножить и его адрес присваивается переменной, умножитьByTwo.
  5. var twoIntoFive = умножить на два (5); вызывает метод объекта getMultiplier(2)multiplier(num) с аргументом 5.
  6. который возвращает простое число 10 в переменную twoIntoFive
  7. умножить на два = 0; заставит сборщик мусора javascript удалить объект getMultiplier(2) из ​​памяти.

person Community    schedule 01.08.2017    source источник
comment
Посмотрите здесь Как работают замыкания JavaScript?   -  person Yordan Nikolov    schedule 01.08.2017
comment
Вы можете обратиться к этой ссылке, чтобы узнать больше о замыканиях. developer.mozilla.org/en/docs/Web/JavaScript/Closures   -  person Rajesh P    schedule 01.08.2017
comment
Да. Просто здесь неправильно используется method (и объект, если это объект js) @downvoter, вы серьезно??   -  person Jonas Wilms    schedule 01.08.2017
comment
@georg ненужно близко. Запрос повторного открытия. Связанный вопрос объясняет, как работают замыкания, но не отвечает на конкретные вопросы оператора.   -  person Tom M    schedule 01.08.2017
comment
@TomM: обман кажется исчерпывающим, и я сомневаюсь, что можно сказать что-то новое, но давайте попробуем!   -  person georg    schedule 01.08.2017
comment
@georg спасибо, я понимаю вашу точку зрения и согласен с тем, что она довольно исчерпывающая в отношении закрытия. Но, как я уже сказал, у OP были конкретные вопросы относительно его конкретного фрагмента кода, и я сомневаюсь, что обманщик ответит на все из них. Я не хотел показаться грубым, но, на мой взгляд, многие вопросы закрываются слишком быстро, что делает stackoverflow довольно токсичным для новых пользователей.   -  person Tom M    schedule 01.08.2017


Ответы (3)


Интересные вопросы.

  1. Почти правильно, за исключением того, что на базовом уровне в javascript на самом деле все функции являются объектами. Кроме того, глядя на две последние переменные, twoIntoFive и tenIntoSix, multiply() является автономной функцией в области getMultiplier() (это означает, что она также содержит ссылку на переменные внутри этой функции).

  2. Точно

  3. Правильно, но имейте в виду, что он все же отличается от getMultiplier.

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

  5. Вот как это работает. Но twoIntoFive на самом деле вызывает возвращенный интерфейс, который ссылается на параметр функции getMultiplier().

  6. Верный.

  7. Это верно. Поскольку вы удалили ссылку на интерфейс, она будет удалена.

Дополнительная литература

Как правило, при возникновении вопросов о javascript рекомендуется обращаться к MDN. Это самая полная документация, которую я когда-либо читал.

Не стесняйтесь исправлять меня или оставлять отзывы, если вы обнаружите ошибки в моем ответе или у вас возникнут дополнительные вопросы

person Tom M    schedule 01.08.2017
comment
Я ошибался насчет 3, 4 и 5. Поскольку в C нет вложенных функций, я предположил, что объект getMultiplier создается в куче с его переменными-членами, но это не дает вам доступа к аргументу. Pascal-вызов вложенной функции имеет одну дополнительную информацию в кадре стека вложенной функции, то есть указатель на кадр стека внешней функции. вам нужно два указателя для вызова вложенной функции, они передаются вmultiplierByTwo как возвращаемое значение из getMultiplier(multiplyBy). один для кадра стека getMultiplier (2), а другой для умножения (число). - person ; 02.08.2017
comment
сборщик мусора помечает, что MultiByTwo имеет ссылку на этот кадр стека и не освобождает его автоматически после возврата из getMultiplier(2). тогда вызов умножитьByTwo(5) равен умножению(5) на передачу указателя на кадр стека функции getMultiplier(2). можно ли сказать, что это происходит здесь? - person ; 02.08.2017
comment
Ссылка у меня не работает. Да, возможность ссылаться и выполнять функцию при объявлении переменной немного сбивает с толку, - person Tom M; 03.08.2017
comment
(...) тогда вызов умноженияByTwo(5) равен умножению(5) с передачей указателя на кадр стека getMultiplier(2). можно ли сказать, что это происходит здесь? Я не уверен в этом, но похоже, что когда вы запускаете скрипт в отладчике. - person Tom M; 03.08.2017
comment
это объяснение вложенных функций лучше всего подходит для понимания замыканий drdobbs.com/architecture-and-design/ - person ; 04.08.2017

На самом деле multiply — это просто функция, а не метод с точки зрения ООП.

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

После вызова getMultiplier со значением параметра значение сохраняется, и функция возвращается (и назначается).

Затем нужно вызвать функцию, ссылка на которую хранится в multiplyByTwo.

Локальная переменная multiplyBy используется для возврата результата. Объект не создается.

person Nina Scholz    schedule 01.08.2017
comment
Но умножитьByTwo и умножитьByTen оба ссылаются на одну и ту же функцию, умножить (число), если в памяти не создано никаких объектов, где умножение (число) получает соответствующее значение умножитьBy? Простой вызов ссылки наmulti(num) будет иметь MultipleBy undefined. - person ; 01.08.2017
comment
он создает новую локальную область видимости для переменных внутри. при возврате функции область видимости для нее сохраняется. - person Nina Scholz; 01.08.2017
comment
@b'stard - нет, они ссылаются на разные функции. Функция (или объекты, если вы хотите их так называть, чем они и являются) создаются и возвращаются каждый раз, когда вы вызываете getMultiplier. Сделайте это getMultiplier(2) == getMultiplier(10) - это неверно - это разные объекты - person Adam; 01.08.2017
comment
Новая локальная область для переменных внутри, основанная на определении getMultiplier(multiplyBy), является своего рода объектом в памяти. Но где? И какой символ он использует для ссылки на это место в памяти? Кроме того, он создает два из них в памяти. Один длямножитьByTwo и один длямножитьByTen. Они должны быть символами для новых объектов, к которым имеет доступ multi(num). Внутреннее представление внутренней функцииmultipli(num) должно иметь некоторый скрытый указатель на объекты getMultiplier, точно так же, как функции C++ имеют скрытый указатель объекта this. - person ; 01.08.2017
comment
Это может быть семантикой, но multiply не нужно знать о getMultiplier как таковом, ему просто нужно знать, что доступно в его локальной области (которая оказывается такой же, как область, созданная при вызове getMultiplier). Среда выполнения JS, очевидно, отслеживает эту область, но я не встречал движка, предоставляющего вам механизм доступа к области. - person Adam; 01.08.2017
comment
@ Адам - ​​что-то в этом роде. Я использую термин C для объекта — типа данных, который занимает реальное место в памяти. - person ; 01.08.2017

По сути, функция есть функция. Я бы не сказал, что multiple(num) — это метод getMultiplier, он просто объявлен в его теле.

Может быть, так было бы легче понять?

var x = function getMultiplier(multiplyBy){
   var y = function (num){
      return multiplyBy * num;
   }

   return y;
}

В любом случае. Как это работает: вызов getMultiplier возвращает функцию «умножить». Функция умножения возвращает multipleBy * num, а getMultiplier возвращает что-то вроде предварительно созданной функции умножения, в которой функцияmultiplier уже заменена параметром getMultiplier.

Таким образом, когда вы вызываете getMultiplier(2), вы получаете следующее:

function multiply(num){
   return 2 * num;
}

Поскольку getMultiplier(num) просто заменяет параметр внутри возвращаемой функции умножения, вы можете передать ей буквально что угодно, и ничего не будет удалено.

person Scharnvirk    schedule 01.08.2017