Кратко
СкопированоФункции — это объект первого класса. Это означает, что функцию можно использовать так же, как и другие типы данных: сохранять в переменную, передавать аргументом и возвращать из функции.
Технически, функция — это объект JavaScript, у которого есть внутренний метод Call, который добавляет возможность вызова функции.
Если вы хотите узнать о синтаксисе функций, читайте статью function.
Как понять
СкопированоВо многих языках функции — это специальные конструкции языка. Они не являются типом данных, и набор операций, которые с ними можно делать ограничен — их можно только объявлять и вызывать.
В JavaScript функция — это тип данных, примерно такой же как объект или строка. Это означает, что с ним можно работать так же, как и с любым другим типом данных — сохранять в переменную, передавать в качестве аргумента функции, возвращать из функций.
О функции удобно думать как об объекте, который поддерживает операцию вызова.
Хранение функции в переменной
СкопированоФункции можно объявлять различными способами. Объявление функции с помощью функционального выражения не что иное, как присваивание безымянной функции переменной:
const answer = function() { console.log('42!')}answer()// 42!
const answer = function() {
console.log('42!')
}
answer()
// 42!
Можно сохранять в переменную и функцию, объявленную другим способом. При этом оба имени функции будут работать:
function answerNumber() { console.log('42!')}const answer = answerNumberanswerNumber()// 42!answer()// 42!
function answerNumber() {
console.log('42!')
}
const answer = answerNumber
answerNumber()
// 42!
answer()
// 42!
Переменная хранит ссылку на функцию, поэтому мы можем создавать столько переменных, сколько нам нужно и все они будут именами функции:
const answer = function() { console.log('42!')}const answerNumber = answerconst fn = answer
const answer = function() {
console.log('42!')
}
const answerNumber = answer
const fn = answer
Передача функции в вызов другой функции
СкопированоФункция может передаваться в качестве аргумента при вызове другой функции.
Например, функция, которая может выполнить произвольную операцию между двумя числами. Два числа хранятся внутри функции, а операция, которую нужно выполнить, передаётся при вызове:
function performOperation(operation) { const a = 10 const b = 99 return operation(a, b)}const sum = performOperation(function(one, two) { return one + two })console.log(sum)// 109const result = performOperation(function(num1, num2) { return num1 ** (num1 / num2)})console.log(result)// 1.2618568830660204
function performOperation(operation) {
const a = 10
const b = 99
return operation(a, b)
}
const sum = performOperation(function(one, two) { return one + two })
console.log(sum)
// 109
const result = performOperation(function(num1, num2) { return num1 ** (num1 / num2)})
console.log(result)
// 1.2618568830660204
Таким образом логика операции может определяться вне функции, что делает её гибкой.
Функции, которые ожидают получить другую функцию в качестве параметра — стандартное явление в JavaScript. Даже встроенные методы, такие как for и filter используют этот подход.
Другой случай использования — колбэки в асинхронном коде. Иногда необходимо выполнить операцию после того, как закончится какое-то действие. Например, когда пользователь кликнет на кнопку. В этом случае используется метод add, который принимает имя события и колбэк, который нужно вызвать при его наступлении:
document.getElementsByTagName('button')[0].addEventListener('click', function() { console.log('пользователь кликнул!')})
document.getElementsByTagName('button')[0].addEventListener('click', function() {
console.log('пользователь кликнул!')
})
Возвращение функции как результат вызова
СкопированоФункцию можно вернуть как результат работы другой функции. Например, можно сохранить данные для математической операции, но не выполнять её сразу, а вернуть функцию, которая выполнит операцию над указанными числами:
function lazySum(a, b) { return function() { return a + b }}
function lazySum(a, b) {
return function() {
return a + b
}
}
Здесь очень легко запутаться во вложенности. При вызове lazy мы передаём два аргумента. Эти аргументы не используются тут же — мы создаём новую функцию, которая складывает два числа и возвращаем её. После вызова lazy мы можем сохранить эту функцию в переменную и использовать её, когда нужно:
const performSum = lazySum(99, 1)console.log(performSum)// function lazySum()console.log(performSum())// 100
const performSum = lazySum(99, 1)
console.log(performSum)
// function lazySum()
console.log(performSum())
// 100
Обратите внимание, что значения параметров a и b остаются доступны внутри вложенной функции. Эта особенность связана с контекстом выполнения и лексическим окружением функции. Такой подход также активно используется при разработке на JavaScript.
На практике
Скопированосоветует
Скопировано🛠 Чтобы понять, что в переменной хранится функция, достаточно воспользоваться оператором typeof — для функций он возвращает строку 'function':
const answer = function() { console.log('42!')}console.log(typeof answer)// 'function'
const answer = function() {
console.log('42!')
}
console.log(typeof answer)
// 'function'
🛠 Так как функция технически является объектом, то у функции есть свойства и методы. Например, свойство length вернёт количество параметров функции:
const answer = function() { console.log('42!')}console.log(answer.length)// 0const sum = function(a, b) { return a + b}console.log(sum.length)// 2
const answer = function() {
console.log('42!')
}
console.log(answer.length)
// 0
const sum = function(a, b) {
return a + b
}
console.log(sum.length)
// 2
🛠 Функциям можно добавлять свойства как обычным объектам. Такой код встречается редко, но не удивляйтесь, если увидите:
const calc = function() {}calc.type = 'numbers'console.log(calc.type)// numbers
const calc = function() {}
calc.type = 'numbers'
console.log(calc.type)
// numbers