Различие - то, что functionOne
выражение function и поэтому только определенный, когда та строка достигнута, тогда как functionTwo
объявление функции и определяется, как только его окружающая функция или сценарий выполняются (из-за подъем ).
, Например, выражение function:
// TypeError: functionOne is not a function
functionOne();
var functionOne = function() {
console.log("Hello!");
};
И, объявление функции:
// Outputs: "Hello!"
functionTwo();
function functionTwo() {
console.log("Hello!");
}
Это также означает, что Вы не можете условно определить функции с помощью объявлений функции:
if (test) {
// Error or misbehavior
function functionThree() { doSomething(); }
}
Вышеупомянутое на самом деле определяет functionThree
независимо от test
значение — если use strict
не в действительности, в этом случае это просто повышает ошибку.
В терминах информатики мы говорим об анонимных функциях и названных функциях. Я думаю, что наиболее важное различие - то, что анонимная функция не связывается с именем, отсюда имя анонимная функция. В JavaScript это - объект первого класса, динамично объявленный во времени выполнения.
Для получения дополнительной информации об анонимных функциях и лямбда-исчислении, Википедия является хорошим началом ( http://en.wikipedia.org/wiki/Anonymous_function ).
Сначала я хочу исправить Greg: function abc(){}
ограничен по объему также — имя abc
определяется в объеме, где с этим определением встречаются. Пример:
function xyz(){
function abc(){};
// abc is defined here...
}
// ...but not here
, Во-вторых, возможно объединить оба стиля:
var xyz = function abc(){};
xyz
будет определенным, как обычно, abc
не определено во всех браузерах, но Internet Проводник — не полагайтесь на то, чтобы он был определенным. Но это будет определено в его теле:
var xyz = function abc(){
// xyz is visible here
// abc is visible here
}
// xyz is visible here
// abc is undefined here
, Если Вы хотите исказить функции на всех браузерах, используйте этот вид объявления:
function abc(){};
var xyz = abc;
В этом случае, и xyz
и abc
псевдонимы того же объекта:
console.log(xyz === abc); // prints "true"
Один неопровержимый довод для использования объединенного стиля является атрибутом "имени" функциональных объектов ( не поддерживаемый Internet Проводник ). В основном при определении функции как [1 136]
function abc(){};
console.log(abc.name); // prints "abc"
, ее имя автоматически присвоено. Но когда Вы определяете его как [1 137]
var abc = function(){};
console.log(abc.name); // prints ""
, его имя является пустым — мы создали анонимную функцию и присвоили ее некоторой переменной.
Другое серьезное основание использовать объединенный стиль состоит в том, чтобы использовать короткое внутреннее имя, чтобы относиться к себе при обеспечении длинного неконфликтующего имени внешних пользователей:
// Assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
// Let it call itself recursively:
shortcut(n - 1);
// ...
// Let it pass itself as a callback:
someFunction(shortcut);
// ...
}
В примере выше мы можем сделать то же с внешним именем, но это будет слишком громоздким (и медленнее).
(Другой способ относиться к себе состоит в том, чтобы использовать arguments.callee
, который все еще относительно длинен, и не поддерживаемый в строгом режиме.)
В глубине души, JavaScript рассматривает оба оператора по-другому. Это - объявление функции:
function abc(){}
abc
здесь определяется везде в текущей области:
// We can call it here
abc(); // Works
// Yet, it is defined down there.
function abc(){}
// We can call it again
abc(); // Works
кроме того, это подняло через return
оператор:
// We can call it here
abc(); // Works
return;
function abc(){}
Это - выражение function:
var xyz = function(){};
xyz
здесь определяется от точки присвоения:
// We can't call it here
xyz(); // UNDEFINED!!!
// Now it is defined
xyz = function(){}
// We can call it here
xyz(); // works
Объявление функции по сравнению с выражением function является настоящей причиной, почему существует различие, продемонстрированное Greg.
Забавный факт:
var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"
Лично, я предпочитаю объявление "выражения function", потому что этот путь я могу управлять видимостью. Когда я определяю функцию как [1 149]
var abc = function(){};
, я знаю, что определил функцию локально. Когда я определяю функцию как [1 150]
abc = function(){};
, я знаю, что определил ее глобально, если это я не определил abc
нигде в цепочке объемов. Этот стиль определения эластичен, даже когда используется в eval()
. В то время как определение
function abc(){};
зависит от контекста и может оставить Вас предполагающий, где это на самом деле определяется, особенно в случае [1 129] — ответ: Это зависит от браузера.
С точки зрения стоимости обслуживания кода, именованные функции более предпочтительны:
Я подозреваю, что последуют больше плюсов для именованных функций. А что указано в качестве преимущества именованных функций, является недостатком анонимных.
Исторически анонимные функции появились из неспособности JavaScript в качестве языка для перечисления членов с именами функций:
{
member:function() { /* How do I make "this.member" a named function? */
}
}
Два фрагмента кода, которые вы разместили там, почти для всех целей будут вести себя одинаково.
Однако разница в поведении заключается в том, что в первом варианте ( var functionOne = function () {}
) эта функция может быть вызвана только после этого места в коде.
Во втором варианте ( function functionTwo ()
) функция доступна для кода, который выполняется выше, где функция объявлена.
Это связано с тем, что в первом варианте функция назначается переменной foo
во время выполнения. Во втором случае функция назначается этому идентификатору, foo
, во время синтаксического анализа.
Дополнительная техническая информация
В JavaScript есть три способа определения функций.
eval ()
, у которого есть свои проблемы. Важная причина состоит в том, чтобы добавить одну и только одну переменную в качестве «корня» вашего пространства имен ...
var MyNamespace = {}
MyNamespace.foo= function() {
}
или
var MyNamespace = {
foo: function() {
},
...
}
Есть много методов для размещения пространств имен. Это стало более важным с появлением множества доступных модулей JavaScript.
Говоря о глобальном контексте, как оператор var
, так и FunctionDeclaration
в конце создают не удаляемое свойство глобального объекта, но значение обоих может быть перезаписано .
Тонкое различие между двумя способами заключается в том, что при запуске процесса Variable Instantiation (до фактического выполнения кода) все идентификаторы, объявленные с помощью var
, будут инициализированы с помощью undefined
, а те, которые используются в FunctionDeclaration
, будут доступны с этого момента, например:
alert(typeof foo); // 'function', it's already available
alert(typeof bar); // 'undefined'
function foo () {}
var bar = function () {};
alert(typeof bar); // 'function'
Назначение bar
FunctionExpression
происходит до тех пор, пока время выполнения.
Глобальное свойство, созданное FunctionDeclaration
, может быть перезаписано без каких-либо проблем, как и значение переменной, например:
function test () {}
test = null;
Еще одно очевидное различие между вашими двумя примерами заключается в том, что первая функция не имеет name, но у второго оно есть, что может быть действительно полезно при отладке (т. е. проверке стека вызовов).
Что касается вашего первого отредактированного примера ( foo = function () {alert ('hello!');};
), это незадекларированное задание, я настоятельно рекомендую вам всегда использовать var
ключевое слово.
С присваиванием, без оператора var
, если указанный идентификатор не найден в цепочке областей видимости, он станет удаляемым свойством глобального объекта.
Кроме того, необъявленные присвоения вызывают ошибку ReferenceError
в ECMAScript 5 в строгом режиме .
Необходимо прочитать:
Примечание : Этот ответ был объединен с другим вопросом , в котором основное сомнение и заблуждение со стороны OP заключалось в том, что идентификаторы объявленный с помощью FunctionDeclaration
, не может быть перезаписан, что не так.