JavaScript: Функциона­льное Выражение vs. Объявление Функции

Источник: «When to Use a Function Expression vs. Function Declaration»
В JavaScript есть два способа создания функции: функциональное выражение и объявление функции. Мы обсудим когда использовать функциональное выражение, а когда объявление и объясним различия между ними.

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

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

function funcDeclaration() {
return 'Объявление функции';
}

let funcExpression = function () {
return 'Функциональное выражение';
}

Что такое объявление функции

Объявление функции — это когда вы создаёте функцию и даёте ей имя. Вы объявляете имя функции, когда пишете ключевое слово function, за которым следует имя функции. Например:

function myFunction() {
// делаем что-то
};

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

Пример объявления функции:

function add (a, b) {
return a + b;
};

Что такое функциональное выражение

Функциональное выражения — это когда вы создаёте функцию и назначаете её переменной. Функция анонимна, это означает, что у неё нет имени. Например:

let myFunction = function() {
// делаем что-то
};

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

Пример функционального выражения:

let add = function (a, b) {
return a + b;
};

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

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

Понимание области видимости в функциональном выражении: различия в подъёме JavaScript

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

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

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

Как выбрать между выражением и объявлением

Итак, когда следует использовать функциональные выражения, а когда объявления функций?

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

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

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

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

Преимущества объявлений функций

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

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

Функциональные выражения также имеют свои преимущества.

Когда выбирать объявление функции или функциональное выражение

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

Используйте объявление функций когда:

Используйте функциональные выражения когда:

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

Раскрытие функционального выражения: Различия в подъёме JavaScript

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

Создание замыкания с функциональными выражениями

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

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

function tabsHandler(index) {
return function tabClickEvent(evt) {
// Выполняем разные вещи с tab.
// Доступ к индексной переменной можно получить отсюда.
};
}

let tabs = document.querySelectorAll('.tab'),
i;

for (i = 0; i < tabs.length; i += 1) {
tabs[i].onclick = tabsHandler(i);
}

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

// Плохой код демонстрирующий, почему необходимо замыкание
let i;

for (i = 0; i < list.length; i += 1) {
document.querySelector('#item' + i).onclick = function doSomething(evt) {
// Делаем что-то с item i
// Но к моменту выполнения этой функции значения i всегда равно list.length
}
}

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

// Плохой код демонстрирующий, почему необходимо замыкание

let list = document.querySelectorAll('.item'),
i,
doSomething = function (evt) {
// Делаем что-то с item i
// Но к моменту выполнения этой функции i уже не то, что было в цикле.
};

for (i = 0; i < list.length; i += 1) {
item[i].onclick = doSomething;
}

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

// The following is good code, demonstrating the use of a closure

let 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 &lt; list.length; i += 1) {
list[i].onclick = doSomethingHandler(i);
}

Передача функционального выражения в качестве аргумента

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

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

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

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

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

let productIds = ['12356', '13771', '15492'];

productIds.forEach(function showProduct(productId) {
...
});

Немедленно вызываемые функциональные выражения (IIFE)

IIFE помогают предотвратить влияние ваших функций и переменных на глобальную область видимости.

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

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

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

(function () {
// код здесь
}());

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

let myModule = (function () {
let 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
};
}());

Заключение

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

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

Дополнительные материалы

Предыдущая Статья

Laravel: Загрузка файлов с помощью FilePond

Следующая Статья

JavaScript: Введение в Fetch API