В этом разделе мы познакомимся c важными особенностями функций в JavaScript, а также с тремя способами объявить функцию.
Объявление Function Declaration
Объявление функции, о котором мы говорили все время до этого, называется в спецификации языкаFunction Declaration
.
Устоявшегося русского перевода нет, также такой синтаксис называют «стандартным» или «обычным» объявлением функции. Чуть дальше мы посмотрим другие варианты создания функций.
Позвольте еще раз выделить основной смысл объявления Function Declaration
:
Другими словами, объявление function func(параметры) { код }
говорит интерпретатору: «создай переменную func
, и положи туда функцию с указанными параметрами и кодом».
При этом func
— на самом деле не «имя функции». Оно совсем никак не привязано к функции!
Это название переменной, в которую будет помещена функция, и из которой она может быть затем удалена, скопирована в другую переменную, и в результате ее какfunc
вызвать будет нельзя:
В частности, невозможно иметь функцию и переменную с одинаковым именем:
В примере выше переменная f
в первой строке получает значение — функцию, а во второй — число 5
. В итоге мы получим переменную со значением f=5
.
Время создания Function Declaration
Функции, объявленные как Function Declaration
, создаются интерпретатором до выполнения кода.
Перед тем, как выполнять первую строку, интерпретатор сканирует код, ищет в немFunction Declaration
и обрабатывает их.
Поэтому их можно вызвать до объявления, например:
Этот код будет работать, т.к. объявление function sayHi
обрабатывается и функция создается до выполнения первой строчки кода.
Попробуем, в зависимости от условия, объявить функцию по-разному:
Какой вызов сработает?
Чтобы это понять — вспомним, как работают функции.
Function Declaration
обрабатываются до выполнения первой строчки кода.
Браузер сканирует код и создает из таких объявлений функции. При этом второе объявление перезапишет первое.
- Дальше, во время выполнения объявления игнорируются (они уже обработаны), как если бы код был таким:
01 |
function sayHi() { alert( 'Прошу вас!' ); } |
02 |
function sayHi() { alert( 'До 18 нельзя' ); } |
Как видно, конструкция if
здесь ни на что не влияет. Об этом говорит сайт https://intellect.icu . По-разному объявить функцию, в зависимости от условия, не получилось.
P.S. Это — правильное с точки зрения спецификации поведение. На момент написания этого раздела ему следуют все браузеры, кроме Firefox.
Объявление Function Expression
Существует альтернативный синтаксис для создания функций, который решает проблемы с «условным» объявлением.
Функцию можно создать и присвоить переменной как самое обычное значение.
Такое объявление называется Function Expression
и выглядит так:
Например:
Такую функцию можно объявить в любом выражении, там где допустимо обычное значение.
Например, вполне допустимо такое объявление массива:
В отличие от объявлений Function Declaration
, которые создаются заранее, до выполнения кода, объявления Function Expression
создают функцию, когда до них доходит выполнение.
Поэтому и пользоваться ими можно только после объявления.
… А вот так — будет:
Благодаря этому свойству Function Expression
можно (и даже нужно) использовать для условного объявления функции:
Функция с вызовом «на месте»
Представим на минуту, что мы создали скрипт, который делает нечто восхитительно-ошеломительное со страницей. Для этого он, конечно же, объявляет свои временные переменные и функции.
Наш скрипт настолько замечательный, что мы хотим дать его другим людям.
В этом случае мы бы хотели, чтобы любой мог вставить скрипт на страницу, и временные переменные и функции скрипта не конфликтовали с теми, которые на ней используются. Например, наш скрипт задает переменные a, b
, и если на странице они уже используются — будет конфликт.
Чтобы его не было, нашему скрипту нужна своя отдельная область видимости, в которой он будет работать.
Для этого используют функции с вызовом «на месте». Такая функция объявляется — и тут же вызывается, вот так:
Теперь внутренние переменные скрипта стали локальными. Даже если в другом месте страницы объявлена своя переменная a
— проблем не будет. Наш скрипт теперь имеет свою, изолированную область видимости.
Эта практика широко используется в библиотеках JavaScript, чтобы временные переменные и функции, которые используются при инициализации, не конфликтовали с внешним кодом.
У функции, которая объявлена таким образом, и тут же вызвана, нет имени. Она никуда не сохраняется, и поэтому не может быть вызвана второй раз. Но в данном случае это и не нужно, ведь задача такой функции обертки — создать отдельную область видимости для скрипта, что она и сделала.
Зачем скобки вокруг функции?
В примерах выше вокруг function() {...}
находятся скобки. Если записать без них — такой код вызовет ошибку:
Эта ошибка произойдет потому, что браузер, видя ключевое слово function
в основном потоке кода, попытается прочитать Function Declaration
, а здесь даже имени нет.
Впрочем, даже если имя поставить, то работать тоже не будет:
Дело в том, что «на месте» разрешено вызывать только Function Expression
.
Общее правило таково:
- Если браузер видит
function
в основном потоке кода - он считает, что этоFunction Declaration
.
- Если же
function
идет в составе более сложного выражения, то он считает, что этоFunction Expression
.
Для этого и нужны скобки - показать, что у нас Function Expression
, который по правилам JavaScript можно вызвать «на месте».
Можно показать это другим способом, например поставив перед функцией оператор:
Главное, чтобы интерпретатор понял, что это Function Expression
, тогда он позволит вызвать функцию «на месте».
Скобки не нужны, если это и так Function Expression
, например в таком вызове:
Функция здесь создается как часть выражения присваивания, поэтому является Function Expression
и может быть вызвана «на месте». При этом, так как сама функция нигде не сохраняется, то она исчезнет, выполнившись, останется только ее результат.
Технически, если функция и так задана как Function Expression
, то она может быть вызвана «на месте» без скобок:
var result = function (a,b) { |
Но из соображений стиля и читаемости скобки вокруг function
рекомендуется ставить:
var result = ( function (a,b) { |
Тогда сразу видно, что в result
записывается не сама функция (result = function...
), а идет «вызов на месте». При чтении такого кода меньше ошибок.
Итого
Функции в JavaScript являются значениями. Их можно присваивать, передавать, создавать в любом месте кода.
- Если функция объявлена в основном потоке кода, то это
Function Declaration
.
- Если функция создана как часть выражения, то это
Function Expression
.
Между этими двумя основными способами создания функций есть следующие различия:
| Function Declaration | Function Expression |
Время создания |
До выполнения первой строчки кода. |
Когда управление достигает строки с функцией. |
Можно вызвать до объявления |
Да (т.к. создается заранее) |
Нет |
Можно объявить в if |
Нет (т.к. создается заранее) |
Да |
Можно вызывать «на месте» |
Нет (ограничение синтаксиса JavaScript) |
Да |
Как общий совет — предпочитайте Function Declaration
.
Сравните по читаемости:
2 |
var f = function () { ... } |
Function Declaration
короче и лучше читается. Дополнительный бонус — такие функции можно вызывать до того, как они объявлены.
Используйте Function Expression
только там, где это действительно нужно. Например, для объявления функции в зависимости от условий.
Комментарии
Оставить комментарий
Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)
Термины: Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)