Пример примера JavaScript: лексическое определение/закрытие - Красноречивый Javascript

Итак, я новичок в программировании, и я пытаюсь изучить JS с помощью книги Eloquent Javascript.

До сих пор так хорошо, пока я не пришел к примеру со следующим кодом

function makeAddFunction(amount) {
  function add(number) {
    return number + amount;
  }
  return add;
}

var addTwo = makeAddFunction(2);
var addFive = makeAddFunction(5);
show(addTwo(1) + addFive(1));

note: show похоже на alert, только он показывает переменные на экране консоли JS, в которую встроено учебное пособие.

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

Я не понимаю, как addTwo и addFive, которые предположительно являются переменными, могут отправлять параметры в функции makeAddFunction и add, а точнее, как функция add знает что параметр, который посылают переменные, является параметром number.

Спасибо за помощь, ребята!

Ответы

Ответ 1

Я думаю, что ключом к пониманию этого примера является понимание того, что функции могут возвращать другие функции (как и любая другая переменная). Документирование этого кода поможет вам понять эту концепцию.

/** 
 * Creates an adder function
 * @param {number} amount Amount to add
 * @return {function}  Method that adds 'amount' to its argument. 
 * See the documentation of add for its signature
 */
function makeAddFunction(amount) {      
  /**
   * Everytime makeAddFunction is called, a new instance of add  is created
   * (and returned) that holds on to its copy of 'amount' (through the closure)
   * @param {number} number value to add to 'amount'
   * @return {number} 'amount' + 'number'
   */
  return function add(number) {
    return number + amount;
  };
}

// addTwo now is a reference to a function that when called
// adds 2 to whatever is passed in
var addTwo = makeAddFunction(2);
// addFive Adds 5 to its argument
var addFive = makeAddFunction(5);
// addTwo(1) = 3, addFive(1) = 6, therefore, output is 9
show(addTwo(1) + addFive(1));

Ответ 2

В javascript функция является первоклассным объектом, то есть ее можно передавать, присваивать переменной и т.д. Переменные addTwo и addFive содержат функции. Эти функции генерируются функцией "factory" makeAddFunction.

Функции, которые добавляют addTwo и addFive, содержат с собой область, которая существовала при их создании. То есть, когда addTwo, например, был создан, параметр "сумма" равнялся 2. Таким образом, addTwo, по сути, является следующей функцией:

function addTwo(number) {
   return number + 2;
}

Когда кто-то вызывает addTwo(), он не передает ничего обратно в makeAddFunction. MakeAddFunction уже запущен и завершен. Однако область, созданная в makeAddFunction (в которой "сумма" равна 2) задерживается в функции addTwo.

Ответ 3

addTwo и addFive являются переменными, но они являются функциональными переменными. Посмотрите typeof(addTwo) - это функция. Как будто вы сделали это:

var addTwo = function(x) { return x + 2; };

Точно так же:

function addTwo(x) { return x + 2; }

(Edit: Как отметил Шмим, они не совсем то же самое. Смотрите здесь для объяснения разницы между ними. )

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

var seven = function(x) { return x + 2; }(5);

Что буквально, на уровне физического машинного кода, то же самое, что: Что эквивалентно для всех целей, относящихся к этому вопросу:

function addTwo(x) { return x + 2; }
var seven = addTwo(5);

Edit:

Возможно, менее запутанным "приквелом" для этого является следующее:

function makeTheAddTwoFunction()
{
    return function(x) { return x + 2; }
}

var addTwo = makeTheAddTwoFunction();

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

Ответ 4

Re: Я не понимаю, как addTwo и addFive, которые предположительно являются переменными, могут отправлять параметры в функции makeAddFunction?

addTwo и addFive являются переменными. Но их значения - не простые скаляры (числа, строки и т.д.). Скорее, их значения являются функциями. Поскольку их значения являются функциями, это нормально, чтобы вызывать эти функции. Например, addTwo(1)

Re: и более конкретно, как добавляет функция, знает, что параметр, который отправляют переменные, - это номер параметра?

Функция add вызывает свой первый номер параметра. Таким образом, когда вы вызываете функцию через переменную, например addOne, первый параметр, присвоенный addOne, становится числом.

ps Если вы думаете про себя: "Я, это довольно сложно!" Тогда вы правы - и что вся цель примера, показать что-то сложное. Как часто вы будете использовать эту технику, это может варьироваться от никогда до каждого так часто.

Ответ 5

Лучший способ подумать о таком фрагменте кода - это подставить значения и интерпретировать в вашем уме

// when this one is invoked
var addTwo = makeAddFunction(2);

// makeAddFunction
// becomes something like
function makeAddFunction(2) {
  function add(number) {
    return number + 2;
  }
  // return a function, that adds
  // 2 to every number it gets
  return add;
}

// therefore this function call
// will add 2 to 1 and return 3
addTwo(1);

Ответ 6

Как всегда, здесь заметки Jibbring о закрытии JavaScript. В нем обсуждаются области применения, контексты выполнения, разрешение переменных/свойств и т.д.

В то время как закрытие JavaScript лексично, контексты выполнения (которые могут содержать свойства) связаны (думаю, Python или Ruby), а не просто "свободные переменные" (как в случае с С# или Scala). Именно по этой причине новые переменные могут быть введены только в новых областях функций. (Современные реализации Mozilla вводят let).