Статьи

Совет: выражения функций против объявлений функций

Эта статья была рецензирована Джеффом Моттом . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!

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

function funcDeclaration() { return 'A function declaration'; } var funcExpression = function () { return 'A function expression'; } 

Различия между объявлениями и выражениями

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

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

Преимущества функциональных выражений

Есть несколько различных способов, которыми функциональные выражения становятся более полезными, чем объявления функций.

  • Как закрытия
  • В качестве аргументов для других функций
  • Как сразу вызванные функциональные выражения (IIFE)

Создание замыканий

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

 function tabsHandler(index) { return function tabClickEvent(evt) { // Do stuff with tab. // The index variable can be accessed from within here. }; } var tabs = document.querySelectorAll('.tab'), i; for (i = 0; i < tabs.length; i += 1) { tabs[i].onclick = tabsHandler(i); } 

Прикрепленные обработчики событий выполняются позднее (после завершения цикла), поэтому необходимо закрытие, чтобы сохранить соответствующее значение цикла for.

 // Bad code, demonstrating why a closure is needed var i; for (i = 0; i < list.length; i += 1) { document.querySelector('#item' + i).onclick = function doSomething(evt) { // Do something with item i // But, by the time this function executes, the value of i is always list.length } } 

Легче понять, почему проблема возникает, извлекая doSomething() из цикла for.

 // Bad code, demonstrating why a closure is needed var list = document.querySelectorAll('.item'), i, doSomething = function (evt) { // Do something with item i. // But, by the time this function executes, the value of i is not what it was in the loop. }; for (i = 0; i < list.length; i += 1) { item[i].onclick = doSomething; } 

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

 // the following is good code, demonstrating the use of closure var list = ['item1', 'item2', 'item3'], i, doSomethingHandler = function (itemIndex) { return function doSomething(evt) { // now this doSomething function can retain knowledge of // the index variable via the itemIndex parameter, // along with other variables that may be available too. console.log('Doing something with ' + list[itemIndex]); }; }; for (i = 0; i < list.length; i += 1) { list[i].onclick = doSomethingHandler(i); } 

Другие хорошие примеры замыканий и как они могут помочь, можно найти в этом FAQ .

Передача в качестве аргументов

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

Их часто можно увидеть в jQuery в форме анонимной функции, например:

 $(document).ready(function () { console.log('An anonymous function'); }); 

Также при использовании таких методов, как forEach() , выражение функции используется для обработки элементов массива. Они также не должны быть анонимными анонимными функциями. Рекомендуется назвать выражение функции, чтобы помочь выразить, что функция должна делать, и помочь в отладке.

 var productIds = ['12356', '13771', '15492']; productIds.forEach(function showProduct(productId) { ... }); 

Сразу же вызванные выражения функций (IIFE)

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

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

Простой пример IIFE:

 (function () { // code in here }()); 

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

 var myModule = (function () { var privateMethod = function () { console.log('A private method'); }, someMethod = function () { console.log('A public method'); }, anotherMethod = function () { console.log('Another public method'); }; return { someMethod: someMethod, anotherMethod: anotherMethod }; }()); 

Вывод

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