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

136 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Именованные функциональные выражения
Обычно то, что называют "именем функции", на самом деле -- всего лишь имя переменной, в которую присвоена функция. К самой функции это "имя" никак не привязано.
Однако, есть в 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-) и предназначено для надёжного рекурсивного вызова функции, даже если она записана в другую переменную.