en.javascript.info/1-js/2-first-steps/21-named-function-expression/article.md
Ilya Kantor 87bf53d076 update
2014-11-16 01:40:20 +03:00

5.9 KiB
Raw Blame History

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

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

Однако, есть в JavaScript способ указать имя, действительно привязанное к функции. Оно называется "Named Function Expression" (сокращённо NFE) или, по-русски, "именованное функциональное выражение". [cut]

Named Function Expression [#functions-nfe]

Простейший пример NFE выглядит так:

var f = function *!*sayHi*/!*(...) { /* тело функции */ };

Проще говоря, NFE -- это Function Expression с дополнительным именем (в примере выше sayHi).

Что же это за имя, которое идёт в дополнение к переменной f, и зачем оно?

Имя функционального выражения (sayHi) имеет особый смысл. Оно доступно только изнутри самой функции.

Это ограничение видимости входит в стандарт JavaScript и поддерживается всеми браузерами, кроме IE8-.

Например:

//+ run
var f = function sayHi(name) {
  alert(sayHi); // изнутри функции - видно (выведет код функции) 
};

alert(sayHi); // снаружи - не видно (ошибка: undefined variable 'sayHi')

Кроме того, имя NFE нельзя перезаписать:

//+ run
var test = function sayHi(name) {
*!*
  sayHi = "тест"; // перезапись
*/!*
  alert(sayHi); // function... (перезапись не удалась)
};

test();

В режиме use strict код выше выдал бы ошибку.

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

[smart header="Устаревшее специальное значение arguments.callee"] Если вы работали с JavaScript, то, возможно, знаете, что для этой цели также служило специальное значение arguments.callee.

Если это название вам ни о чём не говорит -- всё в порядке, читайте дальше, мы обязательно обсудим его в отдельной главе.

Если же вы в курсе, то стоит иметь в виду, что оно официально исключено из современного стандарта. А NFE -- это наше настоящее. [/smart]

Пример использования

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

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

Вспомним, к примеру, функцию-факториал из задачи :

//+ run
function f(n) { 
  return n ? n*f(n-1) : 1;
};

alert( f(5) ); // 120

Попробуем перенести её в другую переменную g:

//+ 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:

//+ 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.

Например:

//+ run
var f = function factorial(n) { /*...*/ };

// в IE8- false
// в остальных браузерах ошибка, т.к. имя factorial не видно
alert(f === factorial);

Все остальные браузеры полностью поддерживают именованные функциональные выражения. [/warn]

Итого

Если функция задана как Function Expression, её можно дать имя. Оно будет доступно только внутри функции (кроме IE8-) и предназначено для надёжного рекурсивного вызова функции, даже если она записана в другую переменную.