Функции в JavaScript: синтаксис, параметры и возврат значения
Основные способы объявления функций
Как объявить функцию с помощью ключевого слова function?
function greet(name) {
return "Привет, " + name + "!";
}
console.log(greet("Анна")); // Привет, Анна!функции js (функции в javascript)
В этом примере функция greet объявлена с использованием синтаксиса function. Ключевое слово function указывает на объявление функции, далее следует имя функции, список параметров в круглых скобках и тело функции в фигурных скобках. Функция может быть вызвана до её объявления благодаря механизму hoisting (поднятие объявлений).
Типичные ошибки:
- Забыто ключевое слово return - функция вернёт undefined.
- Путаница с областью видимости переменных, объявленных внутри функции.
- Использование одного и того же имени функции в одной области видимости вызовет переопределение (последнее объявление побеждает).
Как записать функцию как выражение и присвоить переменной?
Функциональное выражение (function expression) позволяет создавать анонимные функции и присваивать их переменным.
const greet = function(name) {
return "Привет, " + name + "!";
};
console.log(greet("Иван")); // Привет, Иван!В отличие от объявления функции, такое выражение не поднимается (hoisting) - его нельзя вызвать до строки присваивания. Это может быть полезно для контроля порядка выполнения.
Распространённая ошибка: попытка вызвать переменную до её инициализации (ReferenceError). Также анонимные функции усложняют отладку, так как в стеке вызовов не отображается имя функции.
Как использовать стрелочную функцию для лаконичного синтаксиса?
Стрелочные функции (arrow functions) появились в ES6 и предоставляют более краткий синтаксис, особенно для коротких функций.
const greet = (name) => "Привет, " + name + "!";
console.log(greet("Мария")); // Привет, Мария!Если тело функции состоит из одного выражения, можно опустить фигурные скобки и ключевое слово return. Если параметр один, круглые скобки также можно опустить. Стрелочные функции не имеют собственного this и arguments, что делает их удобными для колбэков, но непригодными для методов объектов или конструкторов.
Частая ошибка: использование стрелочной функции в качестве метода объекта, где this указывает не на объект, а на внешний контекст. Также стрелочные функции не могут быть использованы с new (вызовут ошибку).
Как создать именованное функциональное выражение?
Именованное функциональное выражение даёт имя функции внутри неё самой, что полезно для рекурсии или отладки.
const factorial = function fact(n) {
return n <= 1 ? 1 : n * fact(n - 1);
};
console.log(factorial(5)); // 120Имя fact доступно только внутри функции, снаружи оно не видно. Это помогает избежать конфликтов имён.
Ошибка: попытка обратиться к имени fact за пределами функции приведёт к ReferenceError.
Как создать функцию с помощью конструктора Function?
Конструктор Function создаёт функцию из строки кода. Это не рекомендуется из-за проблем безопасности и производительности, но иногда используется для динамической генерации кода.
const sum = new Function('a', 'b', 'return a + b');
console.log(sum(3, 4)); // 7Последний аргумент - тело функции, предшествующие - параметры. Такие функции выполняются в глобальной области видимости.
Опасность: строки кода могут быть подвержены инъекциям. Кроме того, парсинг строки медленнее обычного объявления.
Расширенные примеры работы с функциями
Параметры по умолчанию
function multiply(a, b = 1) {
return a * b;
}
console.log(multiply(5)); // 5
console.log(multiply(5, 2)); // 105 10
Пояснение: параметр b имеет значение по умолчанию 1, поэтому при вызове с одним аргументом он равен 1.
Rest-параметры (сбор остаточных аргументов)
function sumAll(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sumAll(1, 2, 3, 4)); // 1010
Оператор ... собирает все переданные аргументы в массив numbers.
Деструктуризация параметров объекта
function greet({ name, age }) {
return `Привет, ${name}! Тебе ${age} лет.`;
}
console.log(greet({ name: "Петр", age: 30 })); // Привет, Петр! Тебе 30 лет.Привет, Петр! Тебе 30 лет.
Функции высшего порядка (map)
const numbers = [1, 2, 3];
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6][2, 4, 6]
Замыкание (closure)
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 31 2 3
Внутренняя функция "замыкает" переменную count, сохраняя её между вызовами.
Рекурсия: факториал
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
console.log(factorial(5)); // 120120
Метод call и apply
function introduce(greeting) {
return greeting + ", я " + this.name;
}
const person = { name: "Алексей" };
console.log(introduce.call(person, "Здравствуйте")); // Здравствуйте, я Алексей
console.log(introduce.apply(person, ["Привет"])); // Привет, я АлексейЗдравствуйте, я Алексей Привет, я Алексей
Метод bind
const boundIntroduce = introduce.bind(person, "Добрый день");
console.log(boundIntroduce()); // Добрый день, я АлексейДобрый день, я Алексей
Немедленно вызываемая функция (IIFE)
(function() {
var localVar = "Это локальная переменная";
console.log(localVar);
})(); // Это локальная переменнаяЭто локальная переменная
IIFE создаёт изолированную область видимости, что особенно полезно до появления модулей.
Каррирование
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn(...args);
} else {
return (...more) => curried(...args, ...more);
}
};
}
const multiply = (a, b) => a * b;
const curriedMultiply = curry(multiply);
console.log(curriedMultiply(2)(3)); // 66