Функция
Чем каждый раз повторять команды, проще один раз заключить их в функцию.
- Кратко
- Как пишется
- Как понять
- Имя функции
- Параметры
- Функция и переменные
- Стрелочные функции
- Рекурсивные функции
- Контекст функции
- Дока Дог советует
- Алексей Никитченко советует
- Каков типичный случай использования анонимных функций?
- В чём плюс использования стрелочных функций для методов в конструкторе?
- Пусть у нас объявлена функция function Animal () < >.
- Почему JavaScript функции являются объектами первого класса (First-class Objects)?
- Что такое IIFE?
Обновлено 24 августа 2022
Кратко
Скопировать ссылку «Кратко» Скопировано
Функция — это блок из различных команд. С ней легко создавать порядок в коде программы, избавляясь от ненужных повторений и запутанных частей.
Как пишется
Скопировать ссылку «Как пишется» Скопировано
Первый способ — просто объявить функцию в коде (по-английски Function Declaration):
function hello(name) alert(`Привет $ 😊`)>
function hello(name) alert(`Привет $name> 😊`) >
Второй — создать функциональное выражение (Function Expression). Это похоже на первый способ, но здесь функция становится значением переменной:
const hello = function(name) alert(`Привет $ 😊`)>
const hello = function(name) alert(`Привет $name> 😊`) >
Способы написать функцию из примеров выше не одно и тоже (хотя и выглядят почти одинаково 🤔). Основное отличие в том, что если мы использовали Function Declaration, то JavaScript перенесёт функции вверх текущей области видимости. Это называется «поднятие» (или hoisting).
На практике это означает, что мы можем использовать её до своего же объявления. Пишем — заработай, и где-то потом объясняем как. Магия!
hello('Иван') function hello(name) alert(`Привет $ 😊`)>
hello('Иван') function hello(name) alert(`Привет $name> 😊`) >
Использование Function Expression вызовет ошибку:
hello('Иван') const hello = function (name) alert(`Привет $ 😊`)> // hello is not a function
hello('Иван') const hello = function (name) alert(`Привет $name> 😊`) > // hello is not a function
Как понять
Скопировать ссылку «Как понять» Скопировано
Объявление функции расшифровывается так:
- В начале идёт ключевое слово function , чтобы заявить о наших намерениях объявить функцию;
- Затем имя функции, чтобы можно было отличить одну функцию от другой (у нас лаконичное hello , но бывает лаконичное ничего. );
- В круглых скобках мы указываем параметры (можно и без), которые передадим внутрь;
- Наконец, тело функции — это код в фигурных скобках, который выполняется при её вызове.
Вызвать функцию ещё проще. Создадим новую и назовём её make Shawarma :
function makeShawarma(meat) alert(`Ваша шаурма с $ готова 🌯`)>
function makeShawarma(meat) alert(`Ваша шаурма с $meat> готова 🌯`) >
Для вызова сперва пишем имя функции, а затем в круглых скобках указываем аргумент (или аргументы), например, слово курочкой . Мы объявляем: запусти make Shawarma с курочкой внутри.
makeShawarma('курочкой')
makeShawarma('курочкой')
Имя функции
Скопировать ссылку «Имя функции» Скопировано
Функцию стоит называть так, чтобы название объясняло её действие. Так другим людям понятнее читать код, а вам не придётся вспоминать или разбираться, что такое таинственный function Igor Misha Pasha123321 ( ) 🤔. Это же правило касается и переменных: передаём имя — называем name .
Обычно имя функции пишут стилем camelCase и используют в начале глагол. Например create Bear Counter , get Bear Calculator , send Bear Police .
В JavaScript есть два типа функций по признаку имени. В примере ниже функция называется именованной, потому что у неё есть имя.
function namedFunction() <>
function namedFunction() >
Противоположность именованным функциям — анонимные. У таких имени нет:
function() <>
function() >
Они работают одинаково, но по-разному ведут себя в консоли и стеке вызовов. Допустим, мы написали программу, в которой есть ошибка. Если наши функции были именованными, то стек вызовов покажет, какая функция вызвала какую, и что привело к ошибке:
function functionA() function functionB() throw new Error('Ошибочка!') > functionB()> functionA() // Error: Ошибочка!// at functionB (/index.js:3:11)// at functionA (/index.js:6:3)
function functionA() function functionB() throw new Error('Ошибочка!') > functionB() > functionA() // Error: Ошибочка! // at functionB (/index.js:3:11) // at functionA (/index.js:6:3)
Здесь видно, какие функции вызывали какие, и что привело к ошибке, вплоть до номера строки и символа. С анонимными сложнее, поскольку вместо имён функций будут лишь номера строк.
Параметры
Скопировать ссылку «Параметры» Скопировано
При вызове функции можно передать данные, они будут использованы кодом внутри.
Например, функция show Message принимает два параметра под названиями user и message , а потом соединяет их для целого сообщения.
function showMessage(user, message) console.log(user + ': ' + message)>
function showMessage(user, message) console.log(user + ': ' + message) >
При вызове функции ей нужно передать аргументы. Функцию можно вызывать сколько угодно раз с любыми аргументами:
showMessage('Маша', 'Привет!')// Маша: Привет! showMessage('Иван', 'Как делишки?')// Иван: Как делишки?
showMessage('Маша', 'Привет!') // Маша: Привет! showMessage('Иван', 'Как делишки?') // Иван: Как делишки?
Функция и переменные
Скопировать ссылку «Функция и переменные» Скопировано
Переменные внутри функции существуют только внутри этой функции — этот эффект называется областью видимости.
function five() const numberFive = 5> console.log(numberFive)//numberFive is not defined
function five() const numberFive = 5 > console.log(numberFive) //numberFive is not defined
Если пытаться вызвать их снаружи, то возникнет ошибка. В примере выше мы увидим, что number Five не задан, поскольку вне функции мы действительно не задали number Five .
В то же время глобальные переменные можно использовать как снаружи функции, так и внутри:
const numberFour = 4 function five() const numberFive = numberFour + 1 return numberFive> console.log(numberFour)// 4console.log(five())// 5console.log(numberFive)// numberFive is not defined
const numberFour = 4 function five() const numberFive = numberFour + 1 return numberFive > console.log(numberFour) // 4 console.log(five()) // 5 console.log(numberFive) // numberFive is not defined
Вызов глобальной переменной number Four не приводит к ошибке, тогда как переменная number Five по-прежнему существует только внутри функции.
💡 В примере выше было ключевое слово «return». Что это такое и для чего нужно — более подробно раскрыто в отдельной статье про return 😎
Стрелочные функции
Скопировать ссылку «Стрелочные функции» Скопировано
Стрелочная функция записывается намного короче, чем обычная. В самой простой записи ключевое слово function и фигурные скобки не требуются.
const divider = (number) => number / 2
const divider = (number) => number / 2
В многострочных стрелочных функциях кода больше, поэтому они имеют фигурные скобки, но в остальном не отличаются:
const divider = (numerator, denominator) => const result = numerator / denominator return result>
const divider = (numerator, denominator) => const result = numerator / denominator return result >
А ещё у стрелочных функций нет контекста выполнения, но о нём чуть ниже.
Рекурсивные функции
Скопировать ссылку «Рекурсивные функции» Скопировано
Внутри функции можно вызывать её саму — это пример рекурсивной функции.
function fac(n) if (n < 2) return 1 > else return n * fac(n - 1) >> console.log(fac(3))// 6
function fac(n) if (n 2) return 1 > else return n * fac(n - 1) > > console.log(fac(3)) // 6
Если разложить пример, то получится следующая цепочка:
Получается, что fac ( 3 ) это 3 * 2 * 1, то есть 6. Такой подход часто применяется в математических операциях, но не ограничивается ими.
Контекст функции
Скопировать ссылку «Контекст функции» Скопировано
У кода в момент выполнения есть «окружение». Это функция, которая сейчас отрабатывает, это содержащиеся в ней переменные, это глобальные переменные. Всё это и есть контекст.
🐌 Контекст это сложная, но очень важная тема, поэтому мы написали об этом отдельную статью.
На практике
Скопировать ссылку «На практике» Скопировано
Дока Дог советует
Скопировать ссылку «Дока Дог советует» Скопировано
🛠 При написании функции указываются параметры — те переменные, с которыми работает функция. Но возможны случаи, когда не все параметры заданы. Это может быть сделано как специально, например, для использования варианта по умолчанию, так и произойти случайно — ошибка при использовании или неожиданные входные данные.
🛠 Давайте функциям имена, чтобы отладку проводить было проще.
Анонимную функцию будет сложнее отлаживать, потому что в стеке вызовов не будет её имени.
someElement.addEventListener('click', function () throw new Error('Error when clicked!')>)
someElement.addEventListener('click', function () throw new Error('Error when clicked!') >)
someElement.addEventListener('click', function someElementClickHandler() throw new Error('Error when clicked!')>)
someElement.addEventListener('click', function someElementClickHandler() throw new Error('Error when clicked!') >)
🛠 У стрелочных функций можно использовать неявный (implicit) return :
const arrowFunc1 = () => return 42> const arrowFunc2 = () => 42 arrowFunc1() === arrowFunc2()// true// Обе функции возвращают 42
const arrowFunc1 = () => return 42 > const arrowFunc2 = () => 42 arrowFunc1() === arrowFunc2() // true // Обе функции возвращают 42
Также можно возвращать любые структуры и типы данных:
const arrowFunc3 = () => 'строка'const arrowFunc4 = () => ['массив', 'из', 'строк']
const arrowFunc3 = () => 'строка' const arrowFunc4 = () => ['массив', 'из', 'строк']
Чтобы вернуть объект, его необходимо обернуть в скобки. Только так JS поймёт, что мы не открываем тело функции, а возвращаем результат:
const arrowFunc5 = () => (< cat: 'Барс' >) console.log(arrowFunc5())//
const arrowFunc5 = () => ( cat: 'Барс' >) console.log(arrowFunc5()) //
Алексей Никитченко советует
Скопировать ссылку «Алексей Никитченко советует» Скопировано
🛠 Анонимные функции удобно использовать по месту, например передавать в какой-нибудь метод:
[1, 2, 3, 4, 5].map(function (num) return num * 2>)
[1, 2, 3, 4, 5].map(function (num) return num * 2 >)
Или в вызов другой функции:
function makeCouple(recipe) const green = '🍏' const red = '🍎' return recipe(green, red)> const result = makeCouple(function(one, two) < return one + two >)console.log(result)//🍏🍎
function makeCouple(recipe) const green = '🍏' const red = '🍎' return recipe(green, red) > const result = makeCouple(function(one, two) return one + two >) console.log(result) //🍏🍎
В примерах выше мы не объявляем переданную функцию заранее, не даём ей имя, потому что зачем, если в итоге она отработает единожды? Практичнее объявить и сразу использовать где нужно, для чего анонимные функции отлично подходят.
Это не самая простая концепция, она подробно разбирается в статье «Функция как тип данных».