Зачем использовать именованные функциональные выражения?

У нас есть два разных способа выполнения выражения функции в JavaScript:

Именованное функциональное выражение (NFE) :

var boo = function boo () { alert(1); }; 

Анонимное выражение функции :

 var boo = function () { alert(1); }; 

И оба они могут быть вызваны с помощью boo(); , Я действительно не могу понять, почему / когда я должен использовать анонимные функции и когда я должен использовать Named Function Expressions. Какая разница между ними?

В случае анонимного выражения функции функция является анонимной – буквально она не имеет имени. Переменная, которую вы назначаете, имеет имя, но функция не работает. (Обновление: это было верно через ES5. Начиная с ES2015 [aka ES6], часто функция, созданная с анонимным выражением, получает истинное имя, читайте далее …)

Имена полезны. Имена можно увидеть в трассировке стека, стеках вызовов, списках точек останова и т. Д. Имена – это хорошая вещь.

Вы должны остерегаться именованных функциональных выражений в более старых версиях IE (IE8 и ниже), потому что IE ошибочно создает два полностью отдельных объекта функции в два совершенно разных раза (больше в моей статье в блоге Double take ). Если вам нужно поддерживать IE8, лучше всего придерживаться анонимных выражений функций или объявлений функций, но избегайте использования имен функций.

Начиная с ES2015, многие «анонимные» выражения функций создают функции с именами, и это было обусловлено тем, что различные современные JavaScript-движки были достаточно умны в выводе имен из контекста. В ES2015 выражение анонимной функции приводит к функции с именем boo . Это разбросано по всей спецификации, а не определено в одном месте с кучей правил: поиск вхождения «SetFunctionName», в настоящее время найденный в:

  • §12.2.6.9 (семантика инициализатора свойств)
  • §12.14.4 (семантика оператора присваивания)
  • §12.14.5.2 и §12.14.5.4 (семантика присваивания деструкции)
  • §13.3.1.4 (семантика let и const )
  • … и множество других мест.

Краткая версия в основном в любое время, когда выражение анонимной функции появляется в правой части чего-то вроде назначения или инициализации, например:

 var boo = function() { /*...*/ }; 

(или это может быть let или const а не var ) , или

 var obj = { boo: function() { /*...*/ } }; 

или

 doSomething({ boo: function() { /*...*/ } }); 

(последние два – это одно и то же) , получающаяся функция будет иметь имя ( boo , в примерах).

Существует важное и преднамеренное исключение: Присвоение свойства существующему объекту:

 obj.boo = function() { /*...*/ }; // <== Does not get a name 

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

Функции именования полезны, если им нужно ссылаться на себя (например, для рекурсивных вызовов). Действительно, если вы передаете литеральное выражение функции в качестве аргумента непосредственно другой функции, это выражение функции не может напрямую ссылаться на себя в строгом режиме ES5, если оно не указано.

Например, рассмотрите этот код:

 setTimeout(function sayMoo() { alert('MOO'); setTimeout(sayMoo, 1000); }, 1000); 

Невозможно было бы написать этот код достаточно чисто, если бы выражение функции, переданное setTimeout было анонимным; нам нужно было бы назначить его переменной вместо перед вызовом setTimeout . Таким образом, с названным выражением функции, немного короче и аккуратнее.

Исторически было возможно написать такой код, даже используя выражение анонимной функции, используя arguments.callee

 setTimeout(function () { alert('MOO'); setTimeout(arguments.callee, 1000); }, 1000); 

… но arguments.callee устарел, и он строго запрещен в строгом режиме ES5. Поэтому MDN советует:

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

(акцент мой)

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

Он будет доступен только внутри функции (кроме IE8-).

Это имя предназначено для надежного рекурсивного вызова функции, даже если оно записано в другую переменную.

Обратите внимание, что с объявлением функции это невозможно. Это «специальное» имя внутренней функции указывается только в синтаксисе Function Expression.

 var f = function sayHi(name) { alert( sayHi ); // Inside the function you can see the function code }; alert( sayHi ); // (Error: undefined variable 'sayHi') 

Кроме того, имя NFE (Именованное выражение функции) не может быть перезаписано:

 var test = function sayHi(name) { sayHi = "тест"; // try to redefine alert( sayHi ); // function... (redefinition is unsuccessful ) }; test(); 

Использование названных функциональных выражений лучше, если вы хотите иметь возможность ссылаться на рассматриваемую функцию, не полагаясь на устаревшие функции, такие как arguments.callee .

Вы всегда должны использовать выражения функции NAMED.

  1. Вы можете использовать имя этой функции, когда вам нужна recursion.

2. Анонимные функции не помогают при отладке, поскольку вы не можете увидеть имя функции, которая вызывает проблемы.

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

 var foo = function bar() { //some code... }; foo(); bar(); // Error! 

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

  • Выполнить функцию jQuery после выполнения другой функции
  • Зачем переходить по ссылке const вместо значения?
  • в c: func (void) vs. func ()
  • «Правильный» способ указать необязательные аргументы в R-функциях
  • Передача целочисленного значения по ссылке в Python
  • Почему C ++ не поддерживает функции, возвращающие массивы?
  • Синтаксис функции C, типы параметров, объявленные после списка параметров
  • Процедура с аргументом фиктивного аргумента предполагаемой формы должна иметь явный интерфейс
  • Формула Excel для получения цвета ячейки
  • Функции ползунковых скобок
  • Есть ли способ использовать два оператора «...» в функции из R?
  • Interesting Posts
    Давайте будем гением компьютера.