Особенности Функций в JavaScript

В этой главе:

  • Функция - это значение

  • Другие способы определения функций

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

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

  • Разница в обработке функций

  • Вызов анонимных функций на месте

В этой главе мы познакомимся с особенностями функций в javascript, а также рассмотрим другие способы определения функции.

Функция - это значение

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

Рассмотрим простой пример:

1
2
3
4
function foo() {
  var x = "hello";
}
document.write(foo);  //покажет код функции

В этом примере выводится не результат работы функции foo(), а сама функциия - ее код. Теперь разберем пример подробнее. Определение функции: в данном случае ключевое слово function создает функцию и присваивает ее в качестве значения переменной foo. Затем, мы выводим на экран значение переменной foo.

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

1
2
3
4
5
6
7
8
9
function foo() {
  var x = "hello<br>";
  document.write(x);
}
 
var myfunc = foo;
 
myfunc();  //выводит "hello"
foo();     //делает тоже самое

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

Другие способы определения функций

Существует несколько способов определения функций, которые могут оказаться полезными при программировании сценариев или встретиться при просмотре сценариев написанных другими разработчиками: определение именованной функции (которое уже рассматривалось в предыдущей главе), использование анонимных функций и анонимных функций с указанием идентификатора с помощью которого анонимная функция может вызывать саму себя. Рассмотрим каждый из этих способов далее.

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

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

При определении функции создается переменная которой в качестве значения присваивается функция: проще говоря, определение

1
function foo(параметры) {код функции}

сообщает интерпретатору JavaScript - создать переменную foo и присвоить ей функцию с параметрами (или без) и ее код. Так как при определении функции так же создается переменная, то в программе нельзя объявить переменную с таким же именем.

1
2
3
4
function foo() {}  //создается переменная foo в качестве значения которой функция
var foo = 3;       //создаем переменную foo (а она уже до этого была создана)
 
document.write(foo);  //выводит 3

В первой строке создается переменная foo и получает значение - функцию, во второй строке не создается новая переменная, так как переменная с таким именем уже есть, то ей просто присваивается новое значение - 3.

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

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

1
2
3
4
5
var foo = function(str) {  //переменной присваивается функция без имени
  document.write(str);
}
 
foo("JavaScript");

Как видно в примере, в объявлении после слова function нет имени, т.е. создается анонимная функция, которая присваивается переменной foo. Затем происходит вызов функции по имени переменной foo().

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

1
2
3
4
5
6
7
8
var foo = function fact(n) {
  if(n > 1)
    return n * fact(n - 1);  //вызов анонимной функции самой себя
  else
    return 1;
}
 
foo(5);

Этот код определяет анонимную функцию и сохраняет ссылку на нее в переменной foo. Затем происходит вызов функции по имени переменной foo() c аргументом 5. Такая запись на самом не создает функцию с именем fact, но позволяет телу функции ссылаться с помощью этого имени на саму себя.

Разница в обработке функций

Стандартная (именованная) функция находится в основном потоке кода и видна во всем сценарии, она создается в момент входа в область видимости, т.е. сразу. Как это происходит - интерпретатор JavaScript видит скрипт, проверяет его на наличие именованных функций, как только он их находит, то создает эти функции в памяти и только потом начинает выполнять код скрипта. Поэтому такие функции можно вызывать до их определения:

1
2
3
4
5
foo("JavaScript");
 
function foo(str) {
  document.write(str);
}

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

Анонимные функции в отличие от именованных, создаются только в тот момент, когда до них доходит выполнение, поэтому воспользоваться ими можно только после их определения:

1
2
3
4
5
foo("JavaScript");  //не будет работать, так как ее еще не существует
 
var foo = function(str) {
  document.write(str);
}

Чтобы анонимная функция работала, надо записать ее так:

1
2
3
4
5
var foo = function(str) {
  document.write(str);
}
 
foo("JavaScript");

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

1
2
3
4
5
6
7
8
9
var x = 10;
 
if(x > 10) {
  var foo = function() { document.write("x больше 10"); }
} else {
  var foo = function() { document.write("x меньше 10"); }
}
 
foo();

Вызов анонимных функций на месте

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

1
2
3
(function() {/*код функции*/} )();
//или
(function foo() {/*код функции*/} )();

Теперь рассмотрим, зачем вокруг функции нужны скобки. Скобки вокруг функции сообщают интерпретатору JavaScript о том, что используется анонимная функция, которую по правилам JavaScript можно вызвать "на месте". Вторые скобки - это обычный оператор вызова функции, который на месте вызывает анонимную функцию.

Если не указать круглые скобки вокруг анонимной функции, то такой код вызовет ошибку:

1
2
3
function() {/*код функции*/}();
//или
function foo() {/*код функции*/}();  //выглядит как обычная именованная функция

Ошибка произойдет по той причине, что интерпретатор, видя ключевое слово function в основном коде, попытается ее прочитать как обычную функцию, а по правилу JavaScript на месте разрешено вызывать только анонимные функции.

Скобки можно не указывать, если функция является частью выражения:

1
2
3
var sqr = function(n) {
  return n * n;
}(5);  //вызов функции с аргументом 5

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

1
2
3
4
5
var sqr = (function(n) {
  return n * n;
})(5); 
 
document.write(sqr);

Тогда становится сразу видно, что переменной sqr будет присвоено возвращаемое значение, а не сама функция.

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

Действия

Именованная функция

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

Функция создается

До выполнения первой строки кода

В тот момент, когда до нее доходит выполнение кода

Можно вызвать до определения

Да

Нет

Можно определять в условных операторах

Нет

Да

Можно вызвать на месте

Нет

Да