Зачем использовать именованные функциональные выражения?
У нас есть два разных способа выполнения выражения функции в 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
Вы должны всегда использовать выражения именованных функций, вот почему:
-
Вы можете использовать имя этой функции, когда вам нужна рекурсия.
-
Анонимные функции не помогают при отладке, так как вы не видите название функции, которая вызывает проблемы.
-
Когда вы не называете функцию, позже становится сложнее понять, что она делает. Присвоение имени облегчает понимание.
var foo = function bar() {
//some code...
};
foo();
bar(); // Error!
Здесь, например, поскольку строка имени используется в выражении функции, она не объявляется во внешней области видимости. В случае именованных выражений функций имя выражения функции заключено в его собственную область видимости.