Основы JavaScript 2. Функции

Создание функции

Function Declaration

Простейший способ создать функцию — использовать следующий синтаксис:

function runMe() {
    // тело функции
}

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

runMe();// можно вызывать до определения функции

function runMe() {
    // код
}

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

Функциональные выражения - Function Expression

Объявить функцию можно просто присвоив значение переменной:

var executeMe = function () {
    // код
}

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

executeMe();// Ошибка! Функция не определена

var executeMe = function () {
    // код
};

executeMe();// Ок, функция определена и она выполнится

Передача параметров функции

Чаще всего результат выполнения функции зависит от каких-то других переменных. Такие переменные передаются в функцию в качестве параметров:

function shoMessage(message) {
    alert(message);
}

shoMessage("Hello there!");

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

function shoMessage(author, time, message) {
    alert('[' + time + '] ' + author + ': ' + message);
}

shoMessage("Basil", "00:42", "Hello there!");

Возврат значений

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

function dbl(n) {
    return 2 * n;
}

var doubled = dbl(2);
alert(doubled);

Если return в функции не задан или после return ничего нет, то функция возвращает undefined.

Создание функции через new Function

Также для создания функции может использоваться следующий синтаксис:

var killMe = new Function (
    'a, b', // параметры функции
    'return a + b;' // код функции
);

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

Область видимости переменных

Переменные внутри функции, объявленные с помощью var, имеют локальную область видимости. Если за пределами функции есть переменная с таким же именем, то внутри функции бцдет использоваться её локальная переменная. Если Задать переменную без var, то создастся глобальная переменная.

var a = 1,
    b = 2;
function rotate() {
    var a = 3; // локальная переменная не изменит глобальной
    b = 4; // без var меняем глобальную переменную
    var с = 5; // локальная переменная не видна за пределами функции
    d = 6; // без var создали новую глобальную переменную
}
rotate();

alert(a); // 1
alert(b); // 4
alert(c); // Error: c is not undefined
alert(d); // 6

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

Рекурсия

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

Например, чтобы найти факториал числа 7 нужно 7 умножить на факториал числа 6. Факториал 6, в свою очередь, находится как произведение 6 на факториал 5 и т.д. Факториал 1 равен 1. Таким образом, факториал можно рассчитать с помощью рекурсивной функции:

function factorial(n) {
    if(n <= 1) {
        return 1; // базовый случай, когда углубляться дальше не надо
    } else {
        return n * factorial(n - 1);
    }
}
alert(factorial(6));

Именованные функциональные выражения - Named Function Expression

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

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

var factorial = function f(n) {
    return n==1 ? 1 : n*f(n-1);
}
var fctrl = factorial; // копируем функцию в другую переменную

factorial(6); // работает как обычное функциональное выражение
f(6); // Error: f is not defined
fctrl(6); // работает, функция скопировалась

Анонимная функция

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

var showAlert = function() {
    alert("You shall not pass!");
};
setTimeout(showAlert, 3000);

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

setTimeout(function() {
    alert("You shall not pass!");
}, 3000);

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

Замыкание

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

function myCounter() {
    var i = 0; // создается заново с каждым запуском
    i++;
    alert('i = ' + i);
}

myCounter(); // "i = 1"
myCounter(); // "i = 1"
myCounter(); // "i = 1"

Но если функция вернет в return другую функцию, которая будет как-либо использовать локальную перменную, то такая переменная останется в памяти. В таком случае говорят, что переменная "попала в замыкание".

function createCounter() {
    var i = 0;
    return function() {
        i++; // остается в памяти, т.к. "кому-то" нужна
        alert('i = ' + i);
    }
}

var myCounter = createCounter();
myCounter(); // "i = 1"
myCounter(); // "i = 2"
myCounter(); // "i = 3"