Функции могут считаться как одними из ключевых строительных блоков JavaScript программ. Функция — это просто набор команд, разработанных для выполнения определенной задачи, которая исполняется при вызове.

Определение функции

Определение функции (также известное как объявление, или инструкция функции) всегда начинается с ключевого слова function. Затем следует название этой функции, параметры, которые помещаются в скобки. Дальше идут инструкции JavaScript, которые располагаются в фигурных скобках{ } и которые исполняются при вызове функции.

Посмотрим на примере:

function multiply(a, b) {
  return a * b;
}

Наша функция multiply принимает два аргумента (a и b). Внутри фигурных скобок располагается утверждение, которое возвращает результат умножения первого параметра a на второй b.

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

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

Например, предыдущую функцию multiply можно записать следующим образом:

let multiply = function(a, b) { return a * b; };let x = multiply(2,2); // x возвращает 4

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

Еще мы можем определить функцию, основанную на условии. Например, следующая функция addItem сработает, только если num будет равно 1:

let addItem;if (num === 1) {  addItem = function(shoppingList) {    shoppingList.item = 'Apples';  }}

Вызов функции

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

Для того, чтобы вызвать нашу функцию multiply необходимо записать:

multiply(2,2);

В данном случае мы вызываем функцию, которая принимает два аргумента со значениями 2 и 2. Функция исполняется и проходит все инструкции, возвращая значение 4 (2 умноженное на 2).

Функция должна быть в области видимости при вызове, однако определение функции может быть поднято (располагаться ниже вызова в коде), например:

console.log(multiply(2,2));/* ... */function multiply(a,b) { return a * b; }

Область видимости функции — это либо та функция, в которой она определена, либо вся программа, если определение функции находится на глобальном уровне.

Обратите внимание: это работает только со стандартной функцией, а не с функциональным выражением.

Область видимости функции

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

Посмотрим на примере:

// Эти переменные находятся в глобальной области видимости
let a = 10,    b = 3,    name = 'Bruce';
// Эта функция определена глобально
function multiply() {  return a * b;}
multiply(); // returns 30
// Работаем с вложенной функцией
function multiplyAssign() {  let a = 20,      b = 6;    function add() {    return name + ‘ received’ + (a * b);  }    return add();}
function multiplyAssign() {  let a = 20,      b = 6;    function add() {    return name + ‘ received’ + (a * b);  }    return add();}
multiplyAssign(); //возвращает "Bruce received 120"

Вложенные функции и замыкания

Итак, функцию можно вложить в другую функцию! Вложенная (внутренняя) функция является «собственностью» внешней функции. Она также образует замыкание. Замыкание — это выражение (обычно функция), которое может содержать свободные переменные в окружении, связывающем эти переменные («закрывает» выражение).

Например:

function addSquares(a, b) {  function square(x) {    return x * x;  }  return square(a) + square(b);}a = addSquares(2, 3); // возвращает 13b = addSquares(3, 4); // возвращает 25c = addSquares(4, 5); // возвращает 41

Так как вложенная функция образует замыкание, можно вызвать внешнюю функцию и задать аргументы как для внешней, так и для внутренней функции.

Замыкания

Как нам уже известно, мы можем «вкладывать» функции, и JavaScript даст вложенной функции полный доступ ко всем переменным и функциям, определенным внутри внешней функции (а также к переменным и функциям, которые для нее доступны).

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

Посмотрим на примере:

// внешняя функция определяет переменную name
let user = function(name) {     let getName = function() {    return name;
// у внутренней функции есть доступ к переменной "name"   }
// возвращаем внутреннюю функцию, и используем во внешней области видимости
return getName;            }makeAdmin = user('Steve Stevesson');   makeAdmin(); // возвращает "Steve Stevesson"

Объект arguments

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

arguments[i]

В данном случае i — это первый индекс аргумента, начинающийся с нуля. Поэтому первый аргумент, передаваемый в функцию будет arguments[0]. Общее число аргументов можно получить через arguments.length.

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

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

function myConcat(separator) {   let result = ''; // инициализация списка   let i;   // пройдемся циклом по аргументам   for (i = 1; i < arguments.length; i++) {      result += arguments[i] + separator;   }   return result;}

Вы можете передать любое число аргументов в данную функцию, и она соединит каждую строку в новую строку ‘list’:

myConcat(', ', 'fred', 'wilma', 'barney', 'betty');// возвращает "fred, wilma, barney, betty, "
myConcat('; ', 'marge', 'homer', 'lisa', 'bart', 'maggie');// возвращает "marge; homer; lisa; bart; maggie; "
myConcat('. ', 'jerry', 'kramer', 'elaine', 'george', 'newman');// возвращает "jerry. kramer. elaine. george. newman. "

Обратите внимание: переменная arguments только похожа на массив, но это не так. У нее есть пронумерованный индекс и длина. Однако у нее нет всех методов, присущих массиву.

Параметры функции

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

Параметры по умолчанию

В JavaScript параметры функции по умолчанию равняются undefined. Однако в некоторых ситуациях полезно установить значение по умолчанию. Здесь и пригождаются параметры по умолчанию.

Это очень просто воплотить:

function multiply(a, b = 1) {  return a * b;}
multiply(10); // 10

Вы можете установить 1 как значение по умолчанию для переменной b в начале функции.

Оставшиеся параметры

Синтаксис оставшихся параметров позволяет передавать неопределенное количество параметров в функцию.

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

function multiply(multiplier, ...theArgs) {  return theArgs.map(x => multiplier * x);}
let arr = multiply(2, 1, 2, 3);console.log(arr); // [2, 4, 6]

Стрелочные функции

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

function funcName(params) {  return params + 10;}
funcName(2); // 12

А вот та же функция, но записанная как стрелочная:

let funcName = (params) => params + 10
funcName(2); // 12

Та функция, но записанная всего в одну строчку! Очень компактно!

Если у нас нет параметров, стрелочная функция записывается следующим образом:

() => { statements }

Если же у нас всего один параметр, скобки не обязательны:

parameters => { statements }

И наконец, если вы возвращаете выражение, скобки можно убрать:

parameters => expression
// то же самое, что и:
function (parameters){
  return expression;
}

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

Предопределенные функции

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

Заключение

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

Читайте также:


Перевод статьи Timothy Robards: JavaScript Fundamentals: Mastering Functions

Предыдущая статьяКак я встраивал ресурсы в Go
Следующая статьяКак не лажать с JavaScript. Часть 3