update
This commit is contained in:
parent
962caebbb7
commit
87bf53d076
1825 changed files with 94929 additions and 0 deletions
|
@ -0,0 +1,21 @@
|
|||
**Первый код выведет `function ...`, второй -- ошибку во всех браузерах, кроме IE8-.**
|
||||
|
||||
```js
|
||||
//+ run untrusted
|
||||
// обычное объявление функции (Function Declaration)
|
||||
function g() { return 1; };
|
||||
|
||||
alert(g); // функция
|
||||
```
|
||||
|
||||
Во втором коде скобки есть, значит функция внутри является не `Function Declaration`, а частью выражения, то есть `Named Function Expression`. Его имя видно только внутри, снаружи переменная `g` не определена.
|
||||
|
||||
```js
|
||||
//+ run untrusted
|
||||
// Named Function Expression!
|
||||
(function g() { return 1; });
|
||||
|
||||
alert(g); // Ошибка!
|
||||
```
|
||||
|
||||
Все браузеры, кроме IE8-, поддерживают это ограничение видимости и выведут ошибку, `"undefined variable"`.
|
|
@ -0,0 +1,20 @@
|
|||
# Проверка на NFE
|
||||
|
||||
[importance 5]
|
||||
|
||||
Каков будет результат выполнения кода?
|
||||
|
||||
```js
|
||||
function g() { return 1; }
|
||||
|
||||
alert(g);
|
||||
```
|
||||
|
||||
А такого? Будет ли разница, если да -- почему?
|
||||
|
||||
```js
|
||||
(function g() { return 1; });
|
||||
|
||||
alert(g);
|
||||
```
|
||||
|
136
1-js/2-first-steps/21-named-function-expression/article.md
Normal file
136
1-js/2-first-steps/21-named-function-expression/article.md
Normal file
|
@ -0,0 +1,136 @@
|
|||
# Именованные функциональные выражения
|
||||
|
||||
Обычно то, что называют "именем функции", на самом деле -- всего лишь имя переменной, в которую присвоена функция. К самой функции это "имя" никак не привязано.
|
||||
|
||||
Однако, есть в 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-) и предназначено для надёжного рекурсивного вызова функции, даже если она записана в другую переменную.
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue