В этом разделе мы познакомимся 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 только там, где это действительно нужно. Например, для объявления функции в зависимости от условий.
Комментарии