Являются ли именованные функции предпочтительнее анонимных функций в JavaScript?
Возможный дубликат:
JavaScript: var functionName = function() {} против функции functionName() {}
Есть два возможных метода извлечения функции из Javascript:
var foo = function() { ... }
Это немного надумано; Другой распространенный шаблон:
var foo = {
baz: 43,
doSomething: function() {
// ...
}
}
против
function foo() {
// ...
}
Есть ли явная причина отдать предпочтение одному или другому?
Ответы
Ответ 1
Все зависит от того, где вы заявляете свои функции; Подъемный.
Объявления функций и объявления переменных всегда перемещаются ( "поднимаются" ) невидимо в верхнюю часть их области с помощью интерпретатора JavaScript. Функциональные параметры и языковые имена, очевидно, уже есть. Это означает, что код такой:
function foo() {
bar();
var x = 1;
}
фактически интерпретируется следующим образом:
function foo() {
var x;
bar();
x = 1;
}
Обратите внимание, что часть присваивания деклараций не была поднята. Только имя поднимается. Это не относится к объявлениям функций, в которых также будет поднято тело всей функции.
function test() {
foo(); // TypeError "foo is not a function"
bar(); // "this will run!"
var foo = function () { // function expression assigned to local variable 'foo'
alert("this won't run!");
}
function bar() { // function declaration, given the name 'bar'
alert("this will run!");
}
}
test();
В этом случае только объявление функции имеет свое тело, поднятое вверх. Имя "foo" поднимается, но тело остается позади, которое должно быть назначено во время выполнения.
Вы можете дать имена функциям, определенным в выражениях функций, с синтаксисом, как объявление функции. Это не делает это объявлением функции, и имя не попадает в область видимости и не поднимается.
foo(); // TypeError "foo is not a function"
bar(); // valid
baz(); // TypeError "baz is not a function"
bin(); // ReferenceError "bin is not defined"
var foo = function () {}; // anonymous function expression ('foo' gets hoisted)
function bar() {}; // function declaration ('bar' and the function body get hoisted)
var baz = function bin() {}; // named function expression (only 'baz' gets hoisted)
foo(); // valid
bar(); // valid
baz(); // valid
bin(); // ReferenceError "bin is not defined"
Итак, если вы предпочитаете, чтобы функции поднимались вверх, используйте function declaration
, иначе используйте expression
. Я предпочитаю последнее, поскольку я обычно строю объектные литералы с помощью методов function expressions
.
Именованный function expressions
может пригодиться при возникновении ошибок. Консоль скажет вам, что это за функция, вместо того, чтобы указывать anonymous
aka трассировку стека.
Ответ 2
Здесь вы затронули несколько разных вещей, но я постараюсь сначала ответить на ваш главный вопрос.
В общем....
function() {... }
является выражением функции. Синтаксически это на том же уровне, что и 2
или [4,5]
. Это представляет ценность. Таким образом, var foo=function(){... }
будет работать, как и планировалось, каждый раз.
function foo() {... }
является объявлением функции. Может показаться, что это делает то же самое, что и var foo=function(){...}
, но есть небольшая оговорка. Как и его объявление, оно работает аналогично концепции подъема переменных в JS (в основном, все объявления переменных выполняются до того, как какие-либо выражения будут оценены).
Хороший пример отсюда:
function test() {
foo(); // TypeError "foo is not a function"
bar(); // "this will run!"
var foo = function () { // function expression assigned to local variable 'foo'
alert("this won't run!");
}
function bar() { // function declaration, given the name 'bar'
alert("this will run!");
}
}
test();
По существу, переменное поднятие подняло значение до вершины, поэтому этот код эквивалентен (теоретически):
function test() {
var foo;//foo hoisted to top
var bar=function(){//this as well
alert("this will run!");
}
foo(); // TypeError "foo is not a function"
bar(); // "this will run!"
var foo = function () { // function expression assigned to local variable 'foo'
alert("this won't run!");
}
}
NB: Я хотел бы воспользоваться этим замечанием, чтобы сказать, что интерпретаторам JS трудно следовать теории, поэтому не рекомендуется доверять им несколько сомнительное поведение. Здесь вы найдете хороший пример в конце раздела, где теория и практика в конечном итоге не работают (есть также еще некоторые подробности по теме выражений против объявлений).
Интересный факт: function foo() {...}
в скобках преобразует его из объявления в выражение, что может привести к некоторому странному виду кода, например
(function foo() { return 1; })();// 1
foo; //ReferenceError: foo is not defined
Не делайте этого, если у вас нет причин, пожалуйста.
Резюме var foo=function(){... }
- это * sorta kinda * то же самое, что и функция foo(){... }
за исключением того, что первый делает то, что, как вы думаете, он делает там, где вы думаете, а второй странные вещи если вы не заключаете это в скобки, но это портит область видимости, и интерпретаторы JS позволяют вам делать вещи, которые в спецификации рассматриваются как синтаксические ошибки, так что вы можете поверить, что неправильные вещи на самом деле правильные и т. д....
пожалуйста, используйте выражения функций (var f=function(){...}
). Нет реальной причины не делать этого, особенно если учесть, что вы вынуждены это делать, когда используете точечный синтаксис.
На второй вещи вы коснулись.....
Я не совсем уверен, что сказать, это своего рода совершенно отличается от всего остального по этому поводу.
var foo = {
baz: 43,
doSomething:function() {
...
}
}
это известно как буквальный синтаксис объекта. JSON, основанный на этом синтаксисе, является довольно аккуратным способом форматирования данных, и этот синтаксис в JS часто используется для объявления новых объектов, например, для одноэлементных объектов (избегая всего беспорядка с объявлением функции и использованием new), Он также может быть использован таким же образом, как XML, и предпочитают все крутые дети...
В любом случае, в основном объектный литеральный синтаксис работает так:
{ name1: val1, .... namek:valk }
Это выражение является объектом с определенными значениями, инициализированными на нем. Таким образом, var obj={ name1: val1,.... namek:valk }
означает, что:
obj.name1==val1;
obj['name1']==val1;// x['y'] is the same thing as x.y
...
obj.namek==valk;
Так какое отношение это имеет к нашему примеру? В основном ваше выражение часто используется для объявления одноэлементных объектов. Но его также можно использовать для объявления прототипа объекта, так что кто-то может позже сделать var newObj = Object.create(foo), и у newObj будет foo в качестве прототипа.
Посмотрите подробно на наследование прототипов, если вы действительно хотите понять, насколько оно полезно. Дуглас Крокфорд подробно рассказывает об этом в одном из своих многочисленных выступлений).
Ответ 3
Существует несколько преимуществ функций именования
- имена метаанализа.
functionInstance.name
покажет вам имя.
- Что еще более важно, имя будет напечатано в трассировке стека.
- имена также помогают записывать самостоятельно документирующий или грамотный код.
Существует один недостаток названных выражений функций
- IE имеет утечки памяти для NFE
Нет недостатков в функциях деклараций, кроме менее стилистического управления
Ответ 4
Ваш вопрос действительно состоит из двух частей, так как вам необязательно делать анонимные функции, если они назначены переменной или свойству.
Именованный vs анонимный
@Райнос подчеркивает основные моменты. Лучшая часть названных функций состоит в том, что они будут отображаться в трассировке стека. Даже в ситуациях, когда функции присваиваются переменным/свойствам, неплохо дать своим функциям имя, чтобы помочь с отладкой, однако я бы не сказал, что анонимные функции вообще злы. Они служат прекрасной цели:
Являются ли анонимные функции плохой практикой в JavaScript?
Объявление функции vs выражение функции
В этой части вопроса я хотел бы направить вас к этому вопросу, поскольку он, вероятно, охватывает тему гораздо глубже, чем я могу
var functionName = function() {} vs function functionName() {}