# Именованные функциональные выражения Обычно то, что называют "именем функции", на самом деле -- всего лишь имя переменной, в которую присвоена функция. К самой функции это "имя" никак не привязано. Однако, есть в JavaScript способ указать имя, действительно привязанное к функции. Оно называется "Named Function Expression" (сокращённо NFE) или, по-русски, *"именованное функциональное выражение"*. [cut] ## Named Function Expression [#functions-nfe] Простейший пример NFE выглядит так: ```js var f = function *!*sayHi*/!*(...) { /* тело функции */ }; ``` Проще говоря, NFE -- это `Function Expression` с дополнительным именем (в примере выше `sayHi`). Что же это за имя, которое идёт в дополнение к переменной `f`, и зачем оно? **Имя функционального выражения (`sayHi`) имеет особый смысл. Оно доступно только изнутри самой функции.** **Это ограничение видимости входит в стандарт JavaScript и поддерживается всеми браузерами, кроме IE8-.** Например: ```js //+ run var f = function sayHi(name) { alert(sayHi); // изнутри функции - видно (выведет код функции) }; alert(sayHi); // снаружи - не видно (ошибка: undefined variable 'sayHi') ``` **Кроме того, имя NFE нельзя перезаписать:** ```js //+ run var test = function sayHi(name) { *!* sayHi = "тест"; // перезапись */!* alert(sayHi); // function... (перезапись не удалась) }; test(); ``` В режиме `use strict` код выше выдал бы ошибку. **Как правило, имя NFE используется для единственной цели -- позволить изнутри функции вызвать саму себя.** [smart header="Устаревшее специальное значение `arguments.callee`"] Если вы работали с JavaScript, то, возможно, знаете, что для этой цели также служило специальное значение `arguments.callee`. Если это название вам ни о чём не говорит -- всё в порядке, читайте дальше, мы обязательно обсудим его [в отдельной главе](#arguments-callee). Если же вы в курсе, то стоит иметь в виду, что оно официально исключено из современного стандарта. А NFE -- это наше настоящее. [/smart] ## Пример использования NFE используется в первую очередь в тех ситуациях, когда функцию нужно передавать в другое место кода или перемещать из одной переменной в другую. **Внутреннее имя позволяет функции надёжно обращаться к самой себе, где бы она ни находилась.** Вспомним, к примеру, функцию-факториал из задачи [](/task/factorial): ```js //+ run function f(n) { return n ? n*f(n-1) : 1; }; alert( f(5) ); // 120 ``` Попробуем перенести её в другую переменную `g`: ```js //+ run function f(n) { return n ? n*f(n-1) : 1; }; *!* var g = f; f = null; */!* alert( g(5) ); // запуск функции с новым именем - ошибка при выполнении! ``` Ошибка возникла потому что функция из своего кода обращается к своему старому имени `f`. А этой функции уже нет, `f = null`. Для того, чтобы функция всегда надёжно работала, объявим её как Named Function Expression: ```js //+ run var f = function *!*factorial*/!*(n) { return n ? n**!*factorial*/!*(n-1) : 1; }; var g = f; // скопировали ссылку на функцию-факториал в g f = null; *!* alert( g(5) ); // 120, работает! */!* ``` [warn header="В браузере IE8- создаются две функции"] Как мы говорили выше, в браузере IE до 9 версии имя NFE видно везде, что является ошибкой с точки зрения стандарта. ...Но на самом деле ситуация еще забавнее. Старый IE создаёт в таких случаях целых две функции: одна записывается в переменную `f`, а вторая -- в переменную `factorial`. Например: ```js //+ run var f = function factorial(n) { /*...*/ }; // в IE8- false // в остальных браузерах ошибка, т.к. имя factorial не видно alert(f === factorial); ``` Все остальные браузеры полностью поддерживают именованные функциональные выражения. [/warn] ## Итого Если функция задана как Function Expression, её можно дать имя. Оно будет доступно только внутри функции (кроме IE8-) и предназначено для надёжного рекурсивного вызова функции, даже если она записана в другую переменную.