Эта статья была рецензирована Джеффом Моттом . Спасибо всем рецензентам 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 }; }());
Вывод
Как мы уже видели, функциональные выражения не предлагают многого, чего нельзя достичь с помощью объявлений функций, но их использование часто может привести к получению более чистого и читаемого кода. Их широкое использование делает их неотъемлемой частью инструментария каждого разработчика. Используете ли вы функциональные выражения в вашем коде любыми интересными способами, которые я не упомянул выше? Прокомментируйте и дайте мне знать!