Примечание: этот пост был первоначально опубликован в блоге Quick Left 1/6/16.

Иногда мир просто сложнее, чем должен быть. Давайте быстро разберем некоторые распространенные камни преткновения JavaScript на простом английском языке.

Объявление функции и выражение функции

Объявления функций

Объявления функций или операторы функций начинаются с ключевого слова function.

function boilWater(minutes) {
   console.log('Boiling water for ' + minutes + ' minutes');
}

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

boilWater(5); //=> 'Boiling water for 5 minutes'
function boilWater(minutes) { ... };
boilWater(5); //=> 'Boiling water for 5 minutes'

Функциональные выражения

Функциональные выражения - это функции, которые хранятся как переменные.

var boilWater = function(minutes) {
   console.log('Boiling water for ' + minutes + ' minutes');
}

На этот раз при запуске программы переменная boilWater сохраняется в памяти, но выражение еще не вычислено. Пока это не так, значением boilWater будет ключевое слово undefined. Однако после выражения мы можем использовать выражение, как задумано.

boilWater(10);          //=> TypeError: boilWater is not a function...
console.log(boilWater); //=> undefined
var boilWater = function(minutes) { ... };
boilWater(10);          //=> 'Boiling water for 10 minutes'

Когда я должен использовать каждый?

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

Первоклассные функции

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

Вы можете передавать их в качестве аргументов другим функциям;

function forgetfulGreet(fn, milliseconds) {
   console.log('Hello again... uh... ');
   setTimeout(fn, milliseconds);
};
forgetfulGreet(function() { console.log('Marc') }, 2000);
//=> 'Hello again... uh...'
//=> 'Marc'

или функция возвращает другую функцию.

function cardGenerator(suit) { 
   return function(value) { 
      console.log(value + ' of ' + suit);
   }
}; 
var spadesGenerator = cardGenerator('Spades');
spadesGenerator('Four'); //=> 'Four of Spades'

Закрытие

Для удобства мы использовали только один в последнем примере. Замыкания - это не то, что вы, разработчик, можете писать. Это особенность языка JavaScript, которую вы можете использовать и, возможно, уже имеете, даже не зная об этом.

Когда вы создаете функцию внутри другой функции, JavaScript сохраняет любые переменные, которые могут понадобиться вложенной функции при закрытии. В предыдущем примере, когда мы вызываем spadesGenerator, переменная suit избавляется от сборки мусора и становится доступной нам благодаря закрытию.

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

Что теперь?

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