У нас есть два разных способа выполнения выражения функции в JavaScript:
Выражение именованной функции (NFE) :
var boo = function boo () {
alert(1);
};
Выражение анонимной функции :
var boo = function () {
alert(1);
};
И их обоих можно назвать с помощью boo();
. Я действительно не понимаю, почему / когда мне следует использовать анонимные функции и когда я должен использовать выражения именованных функций. Какая между ними разница?
javascript
function
anonymous-function
function-expression
Афшин Мехрабани
источник
источник
Ответы:
В случае выражения анонимной функции функция анонимна - буквально, у нее нет имени. Переменная, которой вы ее назначаете, имеет имя, а функция - нет. (Обновление: это было правдой через ES5. Начиная с ES2015 [также известного как ES6], часто функция, созданная с помощью анонимного выражения, получает настоящее имя [но не автоматический идентификатор], читайте дальше ...)
Имена полезны. Имена можно увидеть в трассировке стека, стеках вызовов, списках точек останова и т. Д. Имена - это хорошая вещь ™.
(Раньше вам приходилось остерегаться именованных функциональных выражений в более старых версиях IE [IE8 и ниже], потому что они по ошибке создавали два полностью отдельных функциональных объекта в два совершенно разных момента [подробнее в моей статье блога Двойной дубль ]. Если вам нужно поддерживают IE8 [!!], вероятно, лучше придерживаться анонимных функциональных выражений или объявлений функций , но избегайте именованных функциональных выражений.)
Одним из ключевых моментов в выражении именованной функции является то, что оно создает идентификатор в области видимости с этим именем для функции в теле функции:
var x = function example() { console.log(typeof example); // "function" }; x(); console.log(typeof example); // "undefined"
Однако, начиная с ES2015, многие «анонимные» функциональные выражения создают функции с именами, и этому предшествовали различные современные движки JavaScript, которые довольно умно выводили имена из контекста. В ES2015 ваше анонимное выражение функции приводит к функции с именем
boo
. Однако даже с семантикой ES2015 + автоматический идентификатор не создается:var obj = { x: function() { console.log(typeof x); // "undefined" console.log(obj.x.name); // "x" }, y: function y() { console.log(typeof y); // "function" console.log(obj.y.name); // "y" } }; obj.x(); obj.y();
Назначение имени функции выполняется с помощью SetFunctionName абстрактной операции используемой в различных операциях в спецификации.
Краткая версия - это в основном каждый раз, когда выражение анонимной функции появляется справа от чего-то вроде присваивания или инициализации, например:
var boo = function() { /*...*/ };
(или это могло быть
let
илиconst
скорее чемvar
) , илиvar obj = { boo: function() { /*...*/ } };
или
doSomething({ boo: function() { /*...*/ } });
(последние два на самом деле одно и то же) , получившаяся функция будет иметь имя (
boo
в примерах).Есть важное и преднамеренное исключение: присвоение свойству существующего объекта:
obj.boo = function() { /*...*/ }; // <== Does not get a name
Это произошло из-за опасений по поводу утечки информации, возникших, когда новая функция находилась в процессе добавления; подробности в моем ответе на другой вопрос здесь .
источник
new
оператор (присвоение всем таким функциям имен делает.constructor
свойство более полезным во время отладки для выяснения того, что, черт возьми, некоторый объект является экземпляром), а также для функциональных литералов, переданных непосредственно в функцию без предварительного присвоения свойству или переменной (например,setTimeout(function () {/*do stuff*/});
). Даже Chrome показывает их, как(anonymous function)
если бы вы не помогли им, назвав их.setTimeout
пример не взял имя из формального аргумента, объявленного дляsetTimeout
, если бы он был. :-) Но да, NFE определенно полезны, если вы знаете, что не будете иметь дело со старыми браузерами, которые их хешируют.Именование функций полезно, если им нужно ссылаться на самих себя (например, для рекурсивных вызовов). Действительно, если вы передаете буквальное функциональное выражение в качестве аргумента непосредственно другой функции, это функциональное выражение не может напрямую ссылаться на себя в строгом режиме 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 советует:(курсив мой)
источник
Если функция указана как выражение функции, ей можно дать имя.
Он будет доступен только внутри функции (кроме IE8-).
var f = function sayHi(name) { alert( sayHi ); // Inside the function you can see the function code }; alert( sayHi ); // (Error: undefined variable 'sayHi')
Это имя предназначено для надежного рекурсивного вызова функции, даже если оно записано в другую переменную.
Кроме того, имя NFE (Named Function Expression) МОЖЕТ быть перезаписано
Object.defineProperty(...)
следующим способом:var test = function sayHi(name) { Object.defineProperty(test, 'name', { value: 'foo', configurable: true }); alert( test.name ); // foo }; test();
Примечание: это невозможно сделать с помощью Декларации функции. Это «специальное» внутреннее имя функции указывается только в синтаксисе выражения функции.
источник
Вы всегда должны использовать именованные функциональные выражения, поэтому:
Вы можете использовать имя этой функции, когда вам нужна рекурсия.
Анонимные функции не помогают при отладке, поскольку вы не можете увидеть имя функции, которая вызывает проблемы.
Когда вы не называете функцию, позже становится труднее понять, что она делает. Если дать ему имя, его будет легче понять.
var foo = function bar() { //some code... }; foo(); bar(); // Error!
Здесь, например, поскольку строка имени используется в выражении функции, она не объявляется во внешней области видимости. В именованных функциональных выражениях имя функционального выражения заключено в его собственную область видимости.
источник
Использование именованных функциональных выражений лучше, если вы хотите иметь возможность ссылаться на рассматриваемую функцию без необходимости полагаться на устаревшие функции, такие как
arguments.callee
.источник