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

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

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

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

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

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

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

Ответ 1

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

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

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

Одним из ключевых моментов в выражении именованной функции является то, что оно создает внутриобъектный идентификатор с этим именем для функции в теле функции:

var x = function example() {
    console.log(typeof example); // "function"
};
x();
console.log(typeof example);     // "undefined"

Ответ 2

Функции именования полезны, если им необходимо ссылаться на себя (например, для рекурсивных вызовов). Действительно, если вы передаете литеральное выражение функции в качестве аргумента непосредственно другой функции, это выражение функции не может напрямую ссылаться на себя в строгом режиме 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() либо , давая функциональным выражениям имя, либо используйте объявление функции, где функция должна вызывать себя.

(акцент мой)

Ответ 3

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

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

var f = function sayHi(name) {
  alert( sayHi ); // Inside the function you can see the function code
};

alert( sayHi ); // (Error: undefined variable 'sayHi')

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

Кроме того, имя NFE (выражение именованной функции) МОЖЕТ быть перезаписано Object.defineProperty(...) следующим образом:

var test = function sayHi(name) {
  Object.defineProperty(test, 'name', { value: 'foo', configurable: true });
  alert( test.name ); // foo
};

test();

Обратите внимание: что с объявлением функции это невозможно сделать. Это "специальное" имя внутренней функции указывается только в синтаксисе выражения функции.

Ответ 4

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

Ответ 5

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

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

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

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

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

foo();
bar(); // Error!

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