var functionName = function () {} против функции functionName () {}

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

Предыдущий разработчик использовал два способа объявления функций, и я не могу понять, есть ли причина этого или нет.

Два способа:

var functionOne = function() {
    // Some code
};
function functionTwo() {
    // Some code
}

Каковы причины использования этих двух разных методов и каковы плюсы и минусы каждого? Есть ли что-нибудь, что можно сделать одним методом, но нельзя сделать другим?

3.12.2008 11:31:07
permadi.com/tutorial/jsFunc/index.html - очень хорошая страница о функциях javascript
uzay95 9.04.2010 11:51:59
С этим связана отличная статья о выражениях именованных функций .
Phrogz 21.04.2011 21:30:10
@CMS ссылки в этой статье: kangax.github.com/nfe/#expr-vs-decl
Upperstage 3.08.2011 14:18:43
Есть две вещи, о которых вам нужно знать: # 1 В JavaScript объявления поднимаются. Это означает, что var a = 1; var b = 2;становится var a; var b; a = 1; b = 2. Поэтому, когда вы объявляете functionOne, он объявляется, но его значение не устанавливается сразу. Принимая во внимание, что так как functionTwo является просто объявлением, он помещается в верхнюю часть области видимости. # 2 functionTwo позволяет получить доступ к свойству name, что очень помогает при попытке отладки чего-либо.
xavierm02 21.08.2012 16:20:22
Да, и кстати, правильный синтаксис с ";" после назначения и без объявления после. Например , function f(){}против var f = function(){};.
xavierm02 21.08.2012 16:27:11
30 ОТВЕТОВ
РЕШЕНИЕ

Разница в том, что functionOneэто выражение функции, и поэтому оно определяется только при достижении этой строки, тогда как functionTwoявляется объявлением функции и определяется, как только выполняются окружающая его функция или скрипт (из-за подъема ).

Например, выражение функции:

// TypeError: functionOne is not a function
functionOne();

var functionOne = function() {
  console.log("Hello!");
};

И объявление функции:

// Outputs: "Hello!"
functionTwo();

function functionTwo() {
  console.log("Hello!");
}

Исторически объявления функций, определенные в блоках, обрабатывались непоследовательно между браузерами. Строгий режим (введенный в ES5) решил эту проблему путем определения объёмов функций в их включающем блоке.

'use strict';    
{ // note this block!
  function functionThree() {
    console.log("Hello!");
  }
}
functionThree(); // ReferenceError

5008
23.04.2020 15:33:07
@ Грег: Кстати, разница не только в том, что они анализируются в разное время. По сути, ваша functionOneпросто переменная, которой назначена анонимная функция, тогда как functionTwoна самом деле это именованная функция. Позвоните .toString()обоим, чтобы увидеть разницу. Это важно в некоторых случаях, когда вы хотите получить название функции программно.
Jason Bunting 5.08.2011 21:18:09
@Jason Bunting .. не уверен, что вы получаете здесь, .toString (), по-видимому, возвращает по существу одно и то же значение (определение функции) для обоих: cl.ly/2a2C2Y1r0J451o0q0B1B
Jon z 9.09.2011 16:29:42
Есть и разные. Первый - function expressionвторой function declaration. Вы можете прочитать больше на эту тему здесь: javascriptweblog.wordpress.com/2010/07/06/…
Michal Kuklis 14.11.2011 06:03:31
@Greg Часть вашего ответа относительно времени разбора и времени выполнения неверна. В JavaScript объявления функций определяются не во время разбора, а во время выполнения. Процесс выглядит следующим образом: исходный код анализируется -> выполняется программа JavaScript -> инициализируется глобальный контекст выполнения -> выполняется создание экземпляра привязки объявления. Во время этого процесса создаются объявления функций (см. Шаг 5 главы 10.5 ).
Šime Vidas 4.01.2012 00:59:56
Терминология для этого явления известна как подъем.
Colin Pear 3.01.2013 07:22:33

Во-первых, я хочу исправить Грега: function abc(){}это тоже ограничено - имя abcопределено в области, где встречается это определение. Пример:

function xyz(){
  function abc(){};
  // abc is defined here...
}
// ...but not here

Во-вторых, можно сочетать оба стиля:

var xyz = function abc(){};

xyzбудет определен как обычно, abcне определен во всех браузерах, кроме Internet Explorer - не полагайтесь на его определение. Но это будет определено внутри его тела:

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 Explorer ). В основном, когда вы определяете функцию, как

function abc(){};
console.log(abc.name); // prints "abc"

его имя присваивается автоматически. Но когда вы определяете это как

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(){}

Это функциональное выражение:

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

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

Интересный факт:

var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"

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

var abc = function(){};

Я знаю, что я определил функцию локально. Когда я определяю функцию как

abc = function(){};

Я знаю, что я определил это глобально, при условии, что я не определил abcнигде в цепочке областей. Этот стиль определения устойчив, даже когда используется внутри eval(). Хотя определение

function abc(){};

зависит от контекста и может заставить вас угадать, где он определен, особенно в случае eval()- ответ: это зависит от браузера.

1934
10.10.2016 20:38:55
Я имею в виду Роборг, но его нигде не найти. Просто: Роборг === Грег. Вот как история может быть переписана в эпоху Интернета. ;-)
Eugene Lazutkin 26.07.2009 02:52:14
var xyz = function abc () {}; console.log (xyz === abc); Все браузеры, которые я тестировал (Safari 4, Firefox 3.5.5, Opera 10.10), выдают «Неопределенная переменная: abc».
NVI 3.12.2009 17:43:04
В целом, я думаю, что этот пост хорошо объясняет различия и преимущества использования объявления функции. Я согласен не согласиться с тем, что выгода от использования назначений выражений функций для переменной, тем более что «выгода», по-видимому, заключается в том, что вы объявляете глобальную сущность ... и все знают, что вы не должны загромождать глобальное пространство имен , правильно? ;-)
natlee75 8.10.2013 16:30:28
По моему мнению, огромная причина для использования именованной функции заключается в том, что отладчики могут использовать имя, чтобы помочь вам разобраться в вашем стеке вызовов или трассировке стека. это отстой, когда вы смотрите на стек вызовов и видите «анонимную функцию» глубиной 10 уровней ...
goat 26.01.2014 18:25:18
var abc = function(){}; console.log(abc.name);больше не производит "", а "abc"вместо этого.
Qwerty 4.05.2018 12:49:49

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

Для получения дополнительной информации об анонимных функциях и лямбда-исчислении Википедия является хорошим началом ( http://en.wikipedia.org/wiki/Anonymous_function ).

25
19.10.2014 22:25:19
Начиная с ES2015 (через шесть с половиной лет после опубликования вашего ответа) обе функции в вопросе названы.
T.J. Crowder 14.12.2019 10:17:15

С точки зрения стоимости обслуживания кода, именованные функции являются более предпочтительными:

  • Независимо от места, где они объявлены (но все еще ограничены областью действия).
  • Более устойчивы к ошибкам, таким как условная инициализация (вы все равно можете переопределить, если хотите).
  • Код становится более читабельным благодаря выделению локальных функций отдельно от функциональности области. Обычно в области действия сначала идет функциональность, за которой следуют объявления локальных функций.
  • В отладчике вы четко увидите имя функции в стеке вызовов вместо «анонимной / оцененной» функции.

Я подозреваю, что больше PROS для именованных функций следуют. И то, что перечислено как преимущество именованных функций, является недостатком для анонимных.

Исторически анонимные функции возникали из-за невозможности JavaScript как языка перечислять членов с именованными функциями:

{
    member:function() { /* How do I make "this.member" a named function? */
    }
}
30
28.12.2015 19:44:15
Есть тест для подтверждения: blog.firsov.net/2010/01/… Тест производительности JS - область применения и именованные функции - Аналитика
Sasha Firsov 4.02.2010 00:45:03

Два фрагмента кода, которые вы разместили там, будут практически для всех целей вести себя одинаково.

Однако разница в поведении заключается в том, что с первым вариантом ( var functionOne = function() {}) эта функция может быть вызвана только после этой точки в коде.

Во втором варианте ( function functionTwo()) функция доступна для кода, который выполняется выше, где функция объявлена.

Это связано с тем, что в первом варианте функция присваивается переменной fooво время выполнения. Во втором случае функция присваивается этому идентификатору fooво время разбора.

Больше технической информации

В JavaScript есть три способа определения функций.

  1. Ваш первый фрагмент показывает выражение функции . Это предполагает использование оператора «функция» для создания функции - результат этого оператора может быть сохранен в любой переменной или свойстве объекта. Таким образом, выражение функции является мощным. Выражение функции часто называют «анонимной функцией», потому что оно не обязательно должно иметь имя,
  2. Ваш второй пример - объявление функции . Это использует оператор "function" для создания функции. Функция становится доступной во время анализа и может вызываться в любом месте этой области. Вы все еще можете сохранить его в переменной или свойстве объекта позже.
  3. Третий способ определения функции - это конструктор «Function ()» , который не показан в исходном посте. Не рекомендуется использовать это, поскольку это работает так же, как eval(), что имеет свои проблемы.
123
28.12.2015 19:47:08

Говоря о глобальном контексте, varоператор и оператор FunctionDeclarationв конце создадут не удаляемое свойство для глобального объекта, но значение обоих может быть перезаписано .

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

Глобальное свойство, созданное с помощью a, FunctionDeclarationможет быть перезаписано без каких-либо проблем, как значение переменной, например:

 function test () {}
 test = null;

Другое очевидное различие между вашими двумя примерами состоит в том, что первая функция не имеет имени, но вторая имеет его, что может быть очень полезно при отладке (то есть проверке стека вызовов).

Что foo = function() { alert('hello!'); };касается вашего отредактированного первого примера ( ), это незадекларированное задание, я настоятельно рекомендую вам всегда использовать varключевое слово.

При присваивании, без varоператора, если указанный идентификатор не найден в цепочке областей действия, он станет удаляемым свойством глобального объекта.

Кроме того, необъявленные назначения выбрасывают в ReferenceErrorECMAScript 5 в строгом режиме .

Должен читать:

Примечание . Этот ответ был объединен с другим вопросом , в котором основное сомнение и неправильное представление со стороны OP заключались в том, что идентификаторы, объявленные с FunctionDeclaration, нельзя перезаписать, что не соответствует действительности.

143
23.05.2017 12:10:54
Я не знал, что функции могут быть перезаписаны в JavaScript! Кроме того, этот порядок разбора является для меня большой точкой продажи. Думаю, мне нужно посмотреть, как я создаю функции.
Xeoncross 8.08.2010 19:43:48
+0 к статье «Демистифицированы выражения функций имен», так как это 404ing. Возможно зеркало ?: kangax.github.com/nfe
Mr_Chimp 29.11.2011 15:10:16
@CMS Хороший. Имейте в виду, хотя я никогда не видел оригинал, поэтому я не знаю, зеркало это или просто другая статья с таким же названием!
Mr_Chimp 29.11.2011 15:25:01
@Mr_Chimp Я уверен, что это так, thewaybackmachine говорит, что он получил 302 во время сканирования, и перенаправление было на ссылку, которую вы предоставили.
John 30.01.2012 15:18:46

Важной причиной является добавление одной и только одной переменной в качестве «корня» вашего пространства имен ...

var MyNamespace = {}
MyNamespace.foo= function() {

}

или

var MyNamespace = {
  foo: function() {
  },
  ...
}

Есть много методов для пространства имен. Это становится все более важным с множеством доступных модулей JavaScript.

Также смотрите Как мне объявить пространство имен в JavaScript?

62
23.05.2017 11:55:19
Похоже, этот ответ был объединен с этим вопросом из другого вопроса, и формулировка может показаться немного не связанной с этим вопросом. Не могли бы вы отредактировать ответ, чтобы он был направлен именно на этот вопрос? (еще раз; это не ваша вина вообще ... просто побочный эффект объединенного вопроса). Вы также можете удалить его, и я думаю, что вы сохранили бы свою репутацию. Или вы можете оставить это; поскольку он старый, он может не иметь большого значения.
Andrew Barber 29.05.2013 21:13:50

Другие комментаторы уже рассмотрели семантическое различие двух вариантов выше. Я хотел бы отметить стилистическую разницу: только вариант «присваивания» может установить свойство другого объекта.

Я часто строю модули JavaScript с таким шаблоном:

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

    exports.publicUtil = function() {
            ...
    };

    return exports;
})();

С этим шаблоном все ваши публичные функции будут использовать присваивание, в то время как ваши приватные функции будут использовать объявление.

(Обратите также внимание, что для присваивания требуется точка с запятой после оператора, в то время как объявление запрещает это.)

91
19.10.2014 22:24:30
Насколько я могу судить, yuiblog.com/blog/2007/06/12/module-pattern - это исходная ссылка на шаблон модуля. (Хотя эта статья использует var foo = function(){...}синтаксис даже для частных переменных.
Sean McMillan 3.06.2011 12:32:22
На самом деле это не совсем так в некоторых старых версиях IE. ( function window.onload() {}была вещь.)
Ry-♦ 21.04.2013 19:42:51

@EugeneLazutkin приводит пример, где он называет назначенную функцию, которую можно использоватьshortcut() как внутреннюю ссылку на себя. Джон Резиг приводит еще один пример - копирование рекурсивной функции, назначенной другому объекту, в своем учебном пособии по Javascript для Learning Advanced . Хотя назначение функций свойствам здесь не является вопросом, я рекомендую активно попробовать учебник - запустите код, нажав кнопку в правом верхнем углу, и дважды щелкните код, чтобы изменить его по своему вкусу.

Примеры из учебника: рекурсивные вызовы в yell():

Тесты не выполняются, когда оригинальный объект ниндзя удаляется. (страница 13)

var ninja = { 
  yell: function(n){ 
    return n > 0 ? ninja.yell(n-1) + "a" : "hiy"; 
  } 
}; 
assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." ); 

var samurai = { yell: ninja.yell }; 
var ninja = null; 

try { 
  samurai.yell(4); 
} catch(e){ 
  assert( false, "Uh, this isn't good! Where'd ninja.yell go?" ); 
}

Если вы назовете функцию, которая будет вызываться рекурсивно, тесты пройдут. (страница 14)

var ninja = { 
  yell: function yell(n){ 
    return n > 0 ? yell(n-1) + "a" : "hiy"; 
  } 
}; 
assert( ninja.yell(4) == "hiyaaaa", "Works as we would expect it to!" ); 

var samurai = { yell: ninja.yell }; 
var ninja = {}; 
assert( samurai.yell(4) == "hiyaaaa", "The method correctly calls itself." );
18
23.05.2017 12:34:59

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

var functionOne = function() {
    // Some code
};

и использовать это как конструктор, как в

var one = new functionOne();

тогда one.constructor.nameне будет определяться. Function.nameне является стандартным, но поддерживается Firefox, Chrome, другими браузерами, производными от Webkit, и IE 9+.

С

function functionTwo() {
    // Some code
}
two = new functionTwo();

можно получить имя конструктора в виде строки с two.constructor.name.

17
17.01.2013 08:48:42
Имя в первом случае не будет определено, потому что это анонимная функция, назначенная переменной. Я думаю, что слово «анонимный» было придумано для вещей, для которых не определено их имя :)
Om Shankar 17.01.2013 06:13:39
В этом примере two = new становится глобальной функцией, потому что нет var
Waqas Tahir 29.08.2015 05:04:03

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

У меня есть код, который мне нужен для запуска с 160 индивидуально разработанными брендами. Большая часть кода находится в общих файлах, но материал, относящийся к брендингу, находится в отдельном файле, по одному для каждого бренда.

Некоторые марки требуют определенных функций, а некоторые нет. Иногда мне приходится добавлять новые функции, чтобы делать новые вещи, специфичные для брендинга. Я рад изменить код общего доступа, но мне не нужно менять все 160 наборов фирменных файлов.

Используя синтаксис переменной, я могу объявить переменную (по существу, указатель на функцию) в общем коде и либо назначить тривиальную функцию-заглушку, либо установить значение null.

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

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

25
28.12.2015 20:26:41

Первый (функция doSomething (x)) должен быть частью нотации объекта.

Второй ( var doSomething = function(x){ alert(x);}) просто создает анонимную функцию и присваивает ее переменной doSomething. Так что doSomething () вызовет функцию.

Вы можете знать , что объявление функции и выражение функции есть.

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

function foo() {
    return 3;
}

ECMA 5 (13.0) определяет синтаксис как
идентификатор функции (FormalParameterList opt ) {FunctionBody}

В вышеупомянутом условии имя функции видимо в пределах своей области видимости и области видимости ее родителя (иначе это было бы недоступно).

И в выражении функции

Выражение функции определяет функцию как часть более крупного синтаксиса выражения (обычно присваивание переменной). Функции, определенные через выражения функций, могут быть именованными или анонимными. Выражения функций не должны начинаться с «function».

// Anonymous function expression
var a = function() {
    return 3;
}

// Named function expression
var a = function foo() {
    return 3;
}

// Self-invoking function expression
(function foo() {
    alert("hello!");
})();

ECMA 5 (13.0) определяет синтаксис как
идентификатор функции opt (FormalParameterList opt ) {FunctionBody}

15
28.12.2015 20:29:40

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

Однако есть разница в том, как и когда объект функции действительно связан с его переменной. Это различие связано с механизмом, называемым переменным подъемом в JavaScript.

По сути, все объявления функций и объявления переменных поднимаются на вершину функции, в которой происходит объявление (поэтому мы говорим, что JavaScript имеет область действия функции ).

  • Когда объявление функции поднято, тело функции «следует», поэтому, когда тело функции вычисляется, переменная будет немедленно привязана к объекту функции.

  • Когда декларация переменной поднята, инициализация не следует, но "оставлена ​​позади". Переменная инициализируется undefinedв начале тела функции, и ей будет присвоено значение в исходном месте в коде. (На самом деле, ему будет присвоено значение в каждом месте, где происходит объявление переменной с тем же именем.)

Порядок подъема также важен: объявления функций имеют приоритет над объявлениями переменных с тем же именем, а последнее объявление функции имеет приоритет над предыдущими объявлениями функций с тем же именем.

Некоторые примеры...

var foo = 1;
function bar() {
  if (!foo) {
    var foo = 10 }
  return foo; }
bar() // 10

Переменная fooподнимается к верхней части функции, инициализируется undefined, так что !fooэто true, так fooназначено 10. fooВне barсферы «S не играет никакой роли и нетронутая.

function f() {
  return a; 
  function a() {return 1}; 
  var a = 4;
  function a() {return 2}}
f()() // 2

function f() {
  return a;
  var a = 4;
  function a() {return 1};
  function a() {return 2}}
f()() // 2

Объявления функций имеют приоритет над объявлениями переменных, а последнее объявление функции «залипает».

function f() {
  var a = 4;
  function a() {return 1}; 
  function a() {return 2}; 
  return a; }
f() // 4

В этом примере aинициализируется с помощью объекта функции, полученного в результате оценки второго объявления функции, а затем присваивается 4.

var a = 1;
function b() {
  a = 10;
  return;
  function a() {}}
b();
a // 1

Здесь сначала поднимается объявление функции, которая объявляет и инициализирует переменную a. Далее эта переменная назначается 10. Другими словами: присваивание не присваивается внешней переменной a.

33
6.02.2013 16:29:20
У вас есть немного странный способ разместить закрывающие скобки. Вы кодер Python? Похоже, вы пытаетесь сделать Javascript похожим на Python. Боюсь, это сбивает с толку других людей. Если бы мне пришлось поддерживать ваш код JavaScript, я бы сначала пропустил ваш код через автоматический prettyprinter.
nalply 14.05.2013 12:46:50
Отличный пост. «Самовыполняющуюся функцию» или «немедленно вызванное выражение функции» должно быть достаточно легко увидеть, и предпочтения его стиля не должны отвлекать от его поста, что является точным и в целом суммирует «подъем». +1
Ricalsin 17.12.2013 18:13:19

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

С

if (condition){
    function myfunction(){
        // Some code
    }
}

это определение myfunctionпереопределит любое предыдущее определение, поскольку оно будет выполнено во время синтаксического анализа.

Пока

if (condition){
    var myfunction = function (){
        // Some code
    }
}

делает правильную работу по определению myfunctionтолько тогда, когда conditionвстречается.

76
29.06.2017 14:08:06
этот пример хорош и близок к совершенству, но может быть улучшен. лучшим примером будет определение var myFunc = null;вне цикла или вне блока if / elseif / else. Затем вы можете условно назначить разные функции одной и той же переменной. В JS лучше назначить отсутствующее значение для нуля, а затем для неопределенного. Следовательно, вы должны сначала объявить myFunction как null, а затем назначить ее позже, условно.
Alexander Mills 26.05.2015 20:31:32

Если бы вы использовали эти функции для создания объектов, вы бы получили:

var objectOne = new functionOne();
console.log(objectOne.__proto__); // prints "Object {}" because constructor is an anonymous function

var objectTwo = new functionTwo();
console.log(objectTwo.__proto__); // prints "functionTwo {}" because constructor is a named function
15
25.10.2013 16:38:22
Я не могу воспроизвести это. console.log(objectOne.__proto__);печатает "functionOne {}" в моей консоли. Любые идеи о том, почему это может иметь место?
Mike 22.03.2015 10:06:25
Я не могу воспроизвести это также.
daremkd 21.01.2016 15:57:23
Это возможность вашего отладчика (отображать «класс» зарегистрированного объекта), и большинство из них способны получить имя даже для выражений анонимных функций в наши дни. Кстати, вы должны пояснить, что между этими двумя экземплярами нет функциональной разницы.
Bergi 21.01.2016 16:26:32

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

Сроки:

Быстрый список:

  • Объявление функции

  • «Анонимное» functionвыражение (которое, несмотря на термин, иногда создает функции с именами)

  • Именованное functionвыражение

  • Инициализатор функции доступа (ES5 +)

  • Выражение функции стрелки (ES2015 +) (которое, как и выражения анонимной функции, не содержит явного имени и может создавать функции с именами)

  • Объявление метода в инициализаторе объекта (ES2015 +)

  • Объявления конструктора и метода в class(ES2015 +)

Объявление функции

Первая форма - это объявление функции , которое выглядит так:

function x() {
    console.log('x');
}

Объявление функции - это объявление ; это не утверждение или выражение. Таким образом, вы не следуете за ним ;(хотя это безвредно).

Объявление функции обрабатывается, когда выполнение входит в контекст, в котором оно появляется, перед выполнением любого пошагового кода. Создаваемой ей функции присваивается собственное имя ( xв примере выше), и это имя помещается в область, в которой появляется объявление.

Поскольку он обрабатывается перед любым пошаговым кодом в том же контексте, вы можете сделать что-то вроде этого:

x(); // Works even though it's above the declaration
function x() {
    console.log('x');
}

До ES2015, спецификация не не охватывает то , что двигатель JavaScript должен делать , если поместить объявление функции внутри структуры управления , как try, if, switch, whileи т.д., как это:

if (someCondition) {
    function foo() {    // <===== HERE THERE
    }                   // <===== BE DRAGONS
}

И поскольку они обрабатываются до запуска пошагового кода, сложно знать, что делать, когда они находятся в структуре управления.

Хотя это не было указано до ES2015, это было допустимое расширение для поддержки объявлений функций в блоках. К сожалению (и неизбежно), разные двигатели делали разные вещи.

Начиная с ES2015, в спецификации сказано, что делать. Фактически, это дает три отдельных действия:

  1. Если в свободном режиме нет в веб-браузере, движок JavaScript должен делать одно
  2. Если в свободном режиме в веб-браузере, движок JavaScript должен делать что-то еще
  3. Если в строгом режиме (браузер или нет), движок JavaScript должен делать еще одну вещь

Правила для свободных режимов хитры, но в строгом режиме объявления функций в блоках просты: они локальны для блока (у них есть область видимости блока , которая также является новой в ES2015), и они поднимаются наверх блока. Так:

"use strict";
if (someCondition) {
    foo();               // Works just fine
    function foo() {
    }
}
console.log(typeof foo); // "undefined" (`foo` is not in scope here
                         // because it's not in the same block)

«Анонимное» functionвыражение

Вторая распространенная форма называется выражением анонимной функции :

var y = function () {
    console.log('y');
};

Как и все выражения, оно оценивается, когда достигается при пошаговом выполнении кода.

В ES5 создаваемая функция не имеет имени (она анонимна). В ES2015, функции по возможности присваивается имя, выводя его из контекста. В приведенном выше примере имя будет y. Нечто подобное происходит, когда функция является значением инициализатора свойства. (Подробности о том, когда это происходит, и правилах, ищите SetFunctionNameв спецификации  - она ​​появляется повсюду .)

Именованное functionвыражение

Третья форма является выражением именованной функции («NFE»):

var z = function w() {
    console.log('zw')
};

Созданная функция имеет собственное имя ( wв данном случае). Как и все выражения, это оценивается, когда оно достигается при пошаговом выполнении кода. Имя функции не добавляется в область, в которой появляется выражение; имя находится в области действия самой функции:

var z = function w() {
    console.log(typeof w); // "function"
};
console.log(typeof w);     // "undefined"

Обратите внимание, что NFE часто являются источником ошибок для реализаций JavaScript. Например, IE8 и более ранние версии обрабатывают NFE совершенно неправильно , создавая две разные функции в два разных времени. Ранние версии Safari также имели проблемы. Хорошей новостью является то, что в текущих версиях браузеров (IE9 и выше, текущий Safari) таких проблем больше нет. (К сожалению, на момент написания статьи IE8 все еще широко используется, и поэтому использование NFE с кодом для Интернета в целом все еще проблематично.)

Инициализатор функции доступа (ES5 +)

Иногда функции могут проникнуть в значительной степени незамеченными; это в случае с функциями доступа . Вот пример:

var obj = {
    value: 0,
    get f() {
        return this.value;
    },
    set f(v) {
        this.value = v;
    }
};
console.log(obj.f);         // 0
console.log(typeof obj.f);  // "number"

Обратите внимание, что когда я использовал функцию, я не использовал ()! Это потому, что это функция доступа для свойства. Мы получаем и устанавливаем свойство обычным способом, но за кулисами вызывается функция.

Вы также можете создавать функции доступа с помощью Object.defineProperty, Object.definePropertiesи менее известный второй аргумент для Object.create.

Выражение функции стрелки (ES2015 +)

ES2015 приносит нам функцию стрелки . Вот один пример:

var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6

Видишь эту n => n * 2вещь, скрывающуюся в map()звонке? Это функция.

Несколько вещей о функциях стрелок:

  1. У них нет своего this. Вместо этого, они близко надthis из контекста , в котором они определены. (Они также закрываются argumentsи, где это уместно super.) Это означает, что thisвнутри них то же самое, что и то, thisгде они созданы, и их нельзя изменить.

  2. Как вы уже заметили, вы не используете ключевое слово function; вместо этого вы используете =>.

Приведенный n => n * 2выше пример является одной из них. Если у вас есть несколько аргументов для передачи функции, вы используете parens:

var a = [1, 2, 3];
var b = a.map((n, i) => n * i);
console.log(b.join(", ")); // 0, 2, 6

(Помните, что Array#mapзапись передается как первый аргумент, а индекс как второй.)

В обоих случаях тело функции является просто выражением; возвращаемое значение функции будет автоматически результатом этого выражения (вы не используете явное return).

Если вы делаете больше, чем просто одно выражение, используйте {}и явное return(если вам нужно вернуть значение), как обычно:

var a = [
  {first: "Joe", last: "Bloggs"},
  {first: "Albert", last: "Bloggs"},
  {first: "Mary", last: "Albright"}
];
a = a.sort((a, b) => {
  var rv = a.last.localeCompare(b.last);
  if (rv === 0) {
    rv = a.first.localeCompare(b.first);
  }
  return rv;
});
console.log(JSON.stringify(a));

Версия без имени { ... }называется функцией стрелки с телом выражения или кратким телом . (Также: краткая функция стрелки.) Функция с { ... }определением тела - это функция стрелки с телом функции . (Также: функция многословной стрелки.)

Объявление метода в инициализаторе объекта (ES2015 +)

ES2015 допускает более короткую форму объявления свойства, которое ссылается на функцию, называемую определением метода ; это выглядит так:

var o = {
    foo() {
    }
};

почти эквивалент в ES5 и более ранних версиях:

var o = {
    foo: function foo() {
    }
};

Разница (кроме многословия) в том, что метод может использовать super, а функция - нет. Так, например, если бы у вас был объект, который определил (скажем) valueOfс использованием синтаксиса метода, его можно было бы использовать super.valueOf()для получения значения, Object.prototype.valueOfкоторое было бы возвращено (прежде чем предположительно делать что-то еще с ним), тогда как вместо этого должна была бы быть версия ES5 Object.prototype.valueOf.call(this).

Это также означает, что метод имеет ссылку на объект, для которого он был определен, поэтому, если этот объект является временным (например, вы передаете его Object.assignкак один из исходных объектов), синтаксис метода может означать, что объект сохраняется в памяти, когда в противном случае он мог быть собран мусором (если механизм JavaScript не обнаруживает эту ситуацию и не обрабатывает ее, если ни один из методов не использует super).

Объявления конструктора и метода в class(ES2015 +)

ES2015 приносит нам classсинтаксис, включая объявленные конструкторы и методы:

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    getFullName() {
        return this.firstName + " " + this.lastName;
    }
}

Выше приведены два объявления функций: одно для конструктора, который получает имя Person, и другое для getFullName, которому назначена функция Person.prototype.

627
11.01.2019 13:58:57
тогда имя wпросто игнорируется?
BiAiB 4.03.2014 13:37:32
@PellePenna: имена функций полезны для многих вещей. На мой взгляд, двумя важными факторами являются рекурсия и имя функции, отображаемой в стеках вызовов, трассировках исключений и тому подобном.
T.J. Crowder 4.03.2014 13:42:57
@ChaimEliyah - «Принятие не означает, что это лучший ответ, это просто означает, что это сработало для человека, который спросил». источник
ScrapCode 10.02.2016 10:19:34
@ АР: Совершенно верно. Забавно, однако, прямо над ним написано: «Лучшие ответы появляются первыми, поэтому их всегда легко найти». Поскольку принятый ответ появляется первым даже над ответами с более высоким рейтингом, тур может быть несколько противоречивым. ;-) Также немного неточно, если мы определяем «лучший» по голосам (что ненадежно, это только то, что у нас есть), «лучшие» ответы отображаются первыми, только если вы используете вкладку «Голоса» - иначе, ответы, которые являются первыми, являются активными или самыми старыми.
T.J. Crowder 10.02.2016 10:32:23
@TJCrowder: Согласен. «Упорядочено по дате» иногда раздражает.
ScrapCode 10.02.2016 10:46:56

Первый пример - объявление функции:

function abc(){}

Второй пример - это выражение функции:

var abc = function() {};

Главное отличие в том, как они поднимаются (поднимаются и декларируются). В первом примере все объявление функции поднято. Во втором примере поднят только var 'abc', его значение (функция) будет неопределенным, а сама функция останется в той позиции, в которой она объявлена.

Проще говоря:

//this will work
abc(param);
function abc(){}

//this would fail
abc(param);
var abc = function() {}

Чтобы узнать больше об этой теме, я настоятельно рекомендую вам эту ссылку

32
9.05.2015 09:37:41
Ваш пример вроде того же, что и верхний ответ
GôTô 5.06.2014 08:34:58
Основной причиной размещения этого ответа было предоставление ссылки внизу. Это был кусок, который мне не хватало, чтобы полностью понять вышеупомянутый вопрос.
sla55er 8.06.2014 05:44:23
Это очень круто, что вы хотели поделиться ссылкой. Но ссылки на дополнительную информацию в SO должны быть просто комментарием к вопросу или вашему любимому ответу. Очень неоптимально было бы загромождать длинную, сложную страницу, подобную этой, с повторяющейся информацией, просто чтобы добавить одну полезную ссылку в конце. Нет, вы не получите очки репутации за предоставление ссылки, но вы будете помогать сообществу.
XML 13.01.2015 00:26:03

Лучшее объяснение ответа Грега

functionTwo();
function functionTwo() {
}

Почему нет ошибки? Нас всегда учили, что выражения выполняются сверху вниз (??)

Потому что:

Объявления функций и объявления переменных всегда hoistedнезаметно перемещаются ( ) в верхнюю часть их содержащей области действия интерпретатором JavaScript. Параметры функций и определяемые языком имена, очевидно, уже есть. Бен Черри

Это означает, что код такой:

functionOne();                  ---------------      var functionOne;
                                | is actually |      functionOne();
var functionOne = function(){   | interpreted |-->
};                              |    like     |      functionOne = function(){
                                ---------------      };

Обратите внимание, что часть назначений объявлений не была поднята. Поднимается только имя.

Но в случае с объявлениями функций также будет поднято все тело функции :

functionTwo();              ---------------      function functionTwo() {
                            | is actually |      };
function functionTwo() {    | interpreted |-->
}                           |    like     |      functionTwo();
                            ---------------
101
23.05.2017 12:26:42
HI suhail спасибо за ясную информацию о функциональной теме. Теперь мой вопрос: какое из них будет первым объявлением в иерархии объявлений: объявлением переменной (functionOne) или объявлением функции (functionTwo)?
Sharathi RB 2.02.2016 12:09:06

В свете аргумента «именованные функции отображаются в следах стека» современные движки JavaScript на самом деле вполне способны представлять анонимные функции.

На момент написания этой статьи V8, SpiderMonkey, Chakra и Nitro всегда ссылаются на именованные функции по именам. Они почти всегда ссылаются на анонимную функцию по ее идентификатору, если она есть.

SpiderMonkey может выяснить имя анонимной функции, возвращаемой другой функцией. Остальные не могут.

Если вы действительно хотите, чтобы ваш итератор и обратные вызовы об успешном выполнении отображались в трассировке, вы могли бы назвать их тоже ...

[].forEach(function iterator() {});

Но по большей части это не стоит переоценивать.

Жгут ( Скрипка )

'use strict';

var a = function () {
    throw new Error();
},
    b = function b() {
        throw new Error();
    },
    c = function d() {
        throw new Error();
    },
    e = {
        f: a,
        g: b,
        h: c,
        i: function () {
            throw new Error();
        },
        j: function j() {
            throw new Error();
        },
        k: function l() {
            throw new Error();
        }
    },
    m = (function () {
        return function () {
            throw new Error();
        };
    }()),
    n = (function () {
        return function n() {
            throw new Error();
        };
    }()),
    o = (function () {
        return function p() {
            throw new Error();
        };
    }());

console.log([a, b, c].concat(Object.keys(e).reduce(function (values, key) {
    return values.concat(e[key]);
}, [])).concat([m, n, o]).reduce(function (logs, func) {

    try {
        func();
    } catch (error) {
        return logs.concat('func.name: ' + func.name + '\n' +
                           'Trace:\n' +
                           error.stack);
        // Need to manually log the error object in Nitro.
    }

}, []).join('\n\n'));

V8

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at e.i (http://localhost:8000/test.js:17:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: j
Trace:
Error
    at j (http://localhost:8000/test.js:20:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: l
Trace:
Error
    at l (http://localhost:8000/test.js:23:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at http://localhost:8000/test.js:28:19
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: n
Trace:
Error
    at n (http://localhost:8000/test.js:33:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: p
Trace:
Error
    at p (http://localhost:8000/test.js:38:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27 test.js:42

SpiderMonkey

func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
e.i@http://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: j
Trace:
j@http://localhost:8000/test.js:20:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: l
Trace:
l@http://localhost:8000/test.js:23:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
m</<@http://localhost:8000/test.js:28:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: n
Trace:
n@http://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: p
Trace:
p@http://localhost:8000/test.js:38:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1

чакра

func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at e.i (http://localhost:8000/test.js:17:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at j (http://localhost:8000/test.js:20:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at l (http://localhost:8000/test.js:23:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at Anonymous function (http://localhost:8000/test.js:28:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at n (http://localhost:8000/test.js:33:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at p (http://localhost:8000/test.js:38:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)

Nitro

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
i@http://localhost:8000/test.js:17:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: j
Trace:
j@http://localhost:8000/test.js:20:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: l
Trace:
l@http://localhost:8000/test.js:23:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
http://localhost:8000/test.js:28:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: n
Trace:
n@http://localhost:8000/test.js:33:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: p
Trace:
p@http://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
12
13.01.2015 03:24:58

Я добавляю свой собственный ответ только потому, что все остальные подробно рассмотрели подъемную часть.

Я долго думал, какой путь лучше, и теперь я знаю , что благодаря http://jsperf.com :)

введите описание изображения здесь

Объявления функций быстрее, и вот что действительно имеет значение в Web Dev, верно? ;)

40
1.05.2015 15:06:55
Я бы сказал, что удобство сопровождения является наиболее важным аспектом большинства кода. Производительность важна, но в большинстве случаев IO может стать более узким местом, чем то, как вы определяете свои функции. Однако есть некоторые проблемы, когда вам нужен каждый бит производительности, который вы можете получить, и это полезно в этих случаях. Также хорошо иметь здесь ответ, который четко определяет четко определенную часть вопроса.
Richard Garside 2.05.2015 15:22:58
Ну, я обнаружил, что с Firefox все по-другому. jsperf.com/sandytest
Sandeep Nayak 17.11.2015 14:15:48
Просто обновление, так как теперь у меня полностью функциональный стиль программирования в JavaScript, я никогда не использую объявления, только выражения функций, чтобы я мог связывать и вызывать свои функции по именам переменных. Проверьте RamdaJS ...
Leon Gaban 28.12.2016 16:56:35
@SandeepNayak Я просто запустил свой собственный тест в Firefox 50.0.0 / Windows 7 0.0.0, и он на самом деле такой же, как у Леона. Поэтому, если ваш тест верен, я бы пришел к выводу, что тесты jsperf не являются ориентировочными, и все они зависят от вашего браузера и / или версии ОС, или от конкретного состояния текущего компьютера в данный конкретный момент.
ocramot 10.01.2017 13:40:22

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

7
28.12.2015 20:32:45

Ответ Грега достаточно хорош, но я все же хотел бы добавить к нему кое-что, чему научился только сейчас, просматривая видео Дугласа Крокфорда .

Функциональное выражение:

var foo = function foo() {};

Функциональное утверждение:

function foo() {};

Оператор function - это просто сокращение для varоператора со functionзначением.

Так

function foo() {};

расширяется до

var foo = function foo() {};

Что расширяется дальше:

var foo = undefined;
foo = function foo() {};

И они оба поднимаются на вершину кода.

Скриншот из видео

24
23.05.2017 12:18:36
Извините, но это неверно - я не знаю, что Крокфорд пытается сказать на этом слайде. Обе функции и объявления переменных всегда поднимаются к вершине своей области видимости. Разница в том, что присваивания переменных (независимо от того, назначаете ли вы их с помощью строки, логического значения или функции) не поднимаются наверх, тогда как тела функций (с помощью объявления функции).
Thomas Heymann 5.10.2015 16:25:35
Посмотрите на эти примеры кода: gist.github.com/cyberthom/36603fbc20de8e04fd09
Thomas Heymann 5.10.2015 16:51:24

Я перечисляю различия ниже:

  1. Объявление функции может быть размещено в любом месте кода. Даже если он вызывается до того, как определение появляется в коде, он выполняется, когда объявление функции фиксируется в памяти или каким-либо образом, до того, как любой другой код на странице начнет выполнение.

    Взгляните на функцию ниже:

    function outerFunction() {
        function foo() {
           return 1;
        }
        return foo();
        function foo() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 2

    Это потому, что во время исполнения это выглядит так:

    function foo() {  // The first function declaration is moved to top
        return 1;
    }
    function foo() {  // The second function declaration is moved to top
        return 2;
    }
    function outerFunction() {
        return foo();
    }
    alert(outerFunction()); //So executing from top to bottom,
                            //the last foo() returns 2 which gets displayed

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

    Та же функция, используя выражения функций:

    function outerFunction() {
        var foo = function() {
           return 1;
        }
        return foo();
        var foo = function() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 1

    Это потому, что во время исполнения это выглядит так:

    function outerFunction() {
       var foo = undefined;
       var foo = undefined;
    
       foo = function() {
          return 1;
       };
       return foo ();
       foo = function() {   // This function expression is not reachable
          return 2;
       };
    }
    alert(outerFunction()); // Displays 1
  2. Не безопасно писать объявления функций в нефункциональных блоках, как будто, потому что они не будут доступны.

    if (test) {
        function x() { doSomething(); }
    }
  3. Выражение именованной функции, подобное приведенному ниже, может не работать в браузерах Internet Explorer до версии 9.

    var today = function today() {return new Date()}
15
28.12.2015 20:35:28
@Arjun В чем проблема, если вопрос задавался годами раньше? Ответ не только приносит пользу OP, но и потенциально всем пользователям SO, независимо от того, когда был задан вопрос. А что плохого в ответах на вопросы, на которые уже есть принятый ответ?
SantiBailors 5.10.2015 12:58:33
@ Арджун, ты должен понять, что отвечать на старые вопросы неплохо. Если бы это было так, у СО был бы такой барьер. Представьте, что есть изменение в API (хотя и не в контексте этого вопроса), и кто-то замечает это и дает ответ с новым API, разве это не должно быть разрешено ?? До тех пор, пока ответ не имеет смысла и не относится к нему, он будет автоматически отклонен и удален. Вам не нужно беспокоиться об этом !!!!
Sudhansu Choudhary 18.10.2015 21:37:08

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

Первый случай - это выражения функций, которые загружаются только тогда, когда интерпретатор достигает этой строки кода. Поэтому, если вы сделаете это следующим образом, вы получите ошибку, что functionOne не является функцией .

functionOne();
var functionOne = function() {
    // Some code
};

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

Во второй строке мы присваиваем ссылку на анонимную функцию для functionOne.

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

functionOne();
function functionOne() {
   // Some code
}
10
28.12.2015 20:42:20

Подъем - это действие интерпретатора JavaScript по перемещению всех объявлений переменных и функций в начало текущей области видимости.

Однако, только фактические декларации подняты. оставляя задания там, где они есть.

  • переменные / функции, объявленные внутри страницы, имеют глобальный доступ к любой точке этой страницы.
  • Переменные / функции, объявленные внутри функции, имеют локальную область видимости. означает, что они доступны / доступны внутри тела функции (области действия), они не доступны вне тела функции.

переменная

Javascript называется свободно типизированным языком. Это означает, что переменные Javascript могут содержать значение любого типа данных . Javascript автоматически заботится об изменении типа переменной на основе значения / литерала, предоставленного во время выполнения.

global_Page = 10;                                               var global_Page;      « undefined
    « Integer literal, Number Type.   -------------------       global_Page = 10;     « Number         
global_Page = 'Yash';                 |   Interpreted   |       global_Page = 'Yash'; « String
    « String literal, String Type.    «       AS        «       global_Page = true;   « Boolean 
var global_Page = true;               |                 |       global_Page = function (){          « function
    « Boolean Type                    -------------------                 var local_functionblock;  « undefined
global_Page = function (){                                                local_functionblock = 777 Number
    var local_functionblock = 777;                              };  
    // Assigning function as a data.
};  

функция

function Identifier_opt ( FormalParameterList_opt ) { 
      FunctionBody | sequence of statements

      « return;  Default undefined
      « return 'some data';
}
  • функции, объявленные внутри страницы, поднимаются наверх страницы, имеющей глобальный доступ.
  • функции, объявленные внутри функционального блока, поднимаются в верхнюю часть блока.
  • Возвращаемое значение функции по умолчанию: « undefined », значение объявления переменной по умолчанию также «undefined»

    Scope with respect to function-block global. 
    Scope with respect to page undefined | not available.

Объявление функции

function globalAccess() {                                  function globalAccess() {      
}                                  -------------------     }
globalAccess();                    |                 |     function globalAccess() { « Re-Defined / overridden.
localAccess();                     «   Hoisted  As   «         function localAccess() {
function globalAccess() {          |                 |         }
     localAccess();                -------------------         localAccess(); « function accessed with in globalAccess() only.
     function localAccess() {                              }
     }                                                     globalAccess();
}                                                          localAccess(); « ReferenceError as the function is not defined

Выражение функции

        10;                 « literal
       (10);                « Expression                (10).toString() -> '10'
var a;                      
    a = 10;                 « Expression var              a.toString()  -> '10'
(function invoke() {        « Expression Function
 console.log('Self Invoking');                      (function () {
});                                                               }) () -> 'Self Invoking'

var f; 
    f = function (){        « Expression var Function
    console.log('var Function');                                   f ()  -> 'var Function'
    };

Функция, назначенная переменной Пример:

(function selfExecuting(){
    console.log('IIFE - Immediately-Invoked Function Expression');
}());

var anonymous = function (){
    console.log('anonymous function Expression');
};

var namedExpression = function for_InternalUSE(fact){
    if(fact === 1){
        return 1;
    }

    var localExpression = function(){
        console.log('Local to the parent Function Scope');
    };
    globalExpression = function(){ 
        console.log('creates a new global variable, then assigned this function.');
    };

    //return; //undefined.
    return fact * for_InternalUSE( fact - 1);   
};

namedExpression();
globalExpression();

JavaScript интерпретируется как

var anonymous;
var namedExpression;
var globalExpression;

anonymous = function (){
    console.log('anonymous function Expression');
};

namedExpression = function for_InternalUSE(fact){
    var localExpression;

    if(fact === 1){
        return 1;
    }
    localExpression = function(){
        console.log('Local to the parent Function Scope');
    };
    globalExpression = function(){ 
        console.log('creates a new global variable, then assigned this function.');
    };

    return fact * for_InternalUSE( fact - 1);    // DEFAULT UNDEFINED.
};

namedExpression(10);
globalExpression();

Вы можете проверить объявление функции, тестирование выражений в различных браузерах, используя jsperf Test Runner


Классы функций конструктора ES5 : объекты функций, созданные с использованием Function.prototype.bind

JavaScript обрабатывает функции как объекты первого класса, поэтому, будучи объектом, вы можете назначать свойства функции.

function Shape(id) { // Function Declaration
    this.id = id;
};
    // Adding a prototyped method to a function.
    Shape.prototype.getID = function () {
        return this.id;
    };
    Shape.prototype.setID = function ( id ) {
        this.id = id;
    };

var expFn = Shape; // Function Expression

var funObj = new Shape( ); // Function Object
funObj.hasOwnProperty('prototype'); // false
funObj.setID( 10 );
console.log( funObj.getID() ); // 10

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

ArrowFunction : ArrowParameters => ConciseBody,

const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; };
console.log( fn(2) ); // Even
console.log( fn(3) ); // Odd
55
28.09.2017 06:35:18
ааа, твой ответ ... разве это не двусмысленно? хорошо написано, хотя +1 для того, чтобы тратить и писать слишком много информации.
Danish 31.01.2016 17:56:52

new Function()может использоваться для передачи тела функции в строку. И, следовательно, это может быть использовано для создания динамических функций. Также передача сценария без выполнения сценария.

var func = new Function("x", "y", "return x*y;");
function secondFunction(){
   var result;
   result = func(10,20);
   console.log ( result );
}

secondFunction()
6
10.05.2016 07:05:46
Хотя это хорошо и верно, как именно это относится к задаче?
Jack Giffin 10.05.2018 21:06:04

В JavaScript есть два способа создания функций:

  1. Объявление функции:

    function fn(){
      console.log("Hello");
    }
    fn();

    Это очень простой, не требующий пояснений, используемый во многих языках и стандартный для всех языков семейства C. Мы объявили функцию, определили ее и выполнили, вызвав ее.

    Что вы должны знать, так это то, что функции на самом деле являются объектами в JavaScript; внутренне мы создали объект для вышеуказанной функции и дали ему имя с именем fn, или ссылка на объект сохраняется в fn. Функции являются объектами в JavaScript; экземпляр функции на самом деле является экземпляром объекта.

  2. Функциональное выражение:

    var fn=function(){
      console.log("Hello");
    }
    fn();

    JavaScript имеет первоклассные функции, то есть создает функцию и присваивает ее переменной так же, как вы создаете строку или число и присваиваете ее переменной. Здесь переменная fn назначается функции. Причиной этого понятия являются функции в JavaScript; fn указывает на экземпляр объекта вышеуказанной функции. Мы инициализировали функцию и присвоили ее переменной. Это не выполнение функции и присвоение результата.

Ссылка: Синтаксис объявления функции JavaScript: var fn = function () {} против функции fn () {}

11
9.04.2017 07:13:56
а как насчет третьего варианта var fn = function fn() {...}?
chharvey 20.08.2016 00:40:27
Привет, Чхарви, не уверен насчет твоего вопроса, я думаю, ты говоришь о выражении функций, о котором я уже упоминал. Однако, если все еще есть некоторая путаница, просто будьте более сложными.
Anoop Rai 23.08.2016 10:00:44
да, я спрашивал о выражении именованной функции. это похоже на ваш вариант № 2 за исключением того, что функция имеет идентификатор. обычно этот идентификатор совпадает с переменной, которой он назначается, но это не всегда так.
chharvey 23.08.2016 10:39:46
Да Выражение именованной функции аналогично моему варианту №2. Наличие идентификатора не обязательно, так как оно не используется. Всякий раз, когда вы будете выполнять выражение функции, вы будете использовать переменную, содержащую объект функции. Идентификатор не имеет смысла.
Anoop Rai 23.08.2016 11:42:19

Они очень похожи с некоторыми небольшими отличиями: первая - это переменная, назначенная анонимной функции (объявление функции), а вторая - нормальный способ создания функции в JavaScript (объявление анонимной функции), у которой есть использование, минусы и плюсы. :

1. Выражение функции

var functionOne = function() {
    // Some code
};

Выражение функции определяет функцию как часть более крупного синтаксиса выражения (обычно присваивание переменной). Функции, определенные с помощью функций Выражения могут быть именованными или анонимными. Выражения функций не должны начинаться с «function» (отсюда круглые скобки вокруг примера самовывоза ниже).

Присвоение переменной функции означает, что никакой Hoisting, поскольку мы знаем, что функции в JavaScript могут Hoist, означает, что их можно вызывать до того, как они будут объявлены, в то время как переменные должны быть объявлены до получения к ним доступа, поэтому в этом случае мы не можем доступ к функции до того, как она объявлена, также это может быть способ написания ваших функций, для функций, которые возвращают другую функцию, такое объявление может иметь смысл, также в ECMA6 и выше вы можете назначить это функции стрелки, которая может использоваться для вызова анонимных функций, также этот способ объявления является лучшим способом создания функций конструктора в JavaScript.

2. Объявление функций

function functionTwo() {
    // Some code
}

Объявление функции определяет именованную переменную функции без необходимости назначения переменной. Объявления функций выполняются как отдельные конструкции и не могут быть вложены в нефункциональные блоки. Полезно думать о них как о родственных братьях объявлений переменных. Так же, как объявления переменных должны начинаться с «var», объявления функций должны начинаться с «function».

Это нормальный способ вызова функции в JavaScript, эта функция может быть вызвана еще до того, как вы объявите ее, поскольку в JavaScript все функции получают Hoisted, но если вы используете 'строгий', это не будет Hoist, как ожидалось, это хороший способ вызывать все нормальные функции, которые не большие по строкам и не являются функциями-конструкторами.

Кроме того, если вам нужна дополнительная информация о том, как работает подъем в JavaScript, перейдите по ссылке ниже:

https://developer.mozilla.org/en-US/docs/Glossary/Hoisting

9
30.07.2017 04:30:14
...also this way of declaring is a better way to create Constructor functions in JavaScriptПодскажите пожалуйста, мне любопытно!
Karl Morrison 13.06.2017 12:44:01
Одна из причин заключается в том, что все встроенные функции-конструкторы в JavaScript созданы как эта функция Number () {[native code]}, и вас не следует путать со встроенными, в дальнейшем ссылки в этом случае безопаснее, и вы заканчиваете до аккуратным кода , но не с помощью подъемно ...
Alireza 13.06.2017 12:56:45

О производительности:

Новые версии V8представили несколько оптимизаций под капотом и сделали то же самое SpiderMonkey.

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

Chrome 62.0.3202 Chrome test

FireFox 55 Тест Firefox

Хром Канарейка 63.0.3225 Chrome Canary test


Anonymousвыражения функций, кажется, имеют лучшую производительность по сравнению с Namedвыражениями функций.


Firefox Chrome Канарейка ХромFirefox named_anonymous Хром канарейка named_anonymous Chrome named_anonymous

10
28.09.2017 05:13:17
Да, эта разница настолько незначительна, что, надеюсь, разработчики позаботятся о том, какой подход более удобен для удовлетворения их конкретных потребностей, а не какой может быть быстрее (вы получите разные результаты jsperf при каждой попытке в зависимости от того, что делает браузер - большинству задач javascript не обязательно заниматься микрооптимизацией до такой степени).
squidbe 26.11.2017 01:41:53
@squidbe Разницы нет. Смотрите здесь: jsperf.com/empty-tests-performance
Jack Giffin 10.05.2018 21:10:00

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

  1. Наличие (объем) функции

Следующее работает, потому что function add()ограничено до ближайшего блока:

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

function add(a, b){
  return a + b;
}

Следующее не работает, потому что переменная вызывается до назначения значения функции переменной add.

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

var add=function(a, b){
  return a + b;
}

Приведенный выше код по функциональности идентичен приведенному ниже. Обратите внимание, что явное присвоение add = undefinedявляется излишним, потому что просто делать var add;это точно так же, как var add=undefined.

var add = undefined;

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

add = function(a, b){
  return a + b;
}

Следующее не работает, потому что var add=superseeds function add().

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

var add=function add(a, b){
  return a + b;
}

  1. (функция) .name

Имя функции function thefuncname(){}является thefuncname , когда она объявлена таким образом.

function foobar(a, b){}

console.log(foobar.name);

var a = function foobar(){};

console.log(a.name);

В противном случае, если функция объявлена ​​как function(){}, функция .name является первой переменной, используемой для хранения функции.

var a = function(){};
var b = (function(){ return function(){} });

console.log(a.name);
console.log(b.name);

Если для функции не заданы переменные, то именем функции является пустая строка ( "").

console.log((function(){}).name === "");

Наконец, хотя переменная, которой назначена функция, изначально задает имя, последующие переменные, установленные для функции, не меняют имя.

var a = function(){};
var b = a;
var c = b;

console.log(a.name);
console.log(b.name);
console.log(c.name);

  1. Представление

В Google V8 и Firefox Spidermonkey может быть небольшая разница в компиляции JIST на несколько микросекунд, но в конечном итоге результат будет точно таким же. Чтобы доказать это, давайте рассмотрим эффективность JSPerf в микробенчмарках, сравнив скорость двух пустых фрагментов кода. В тестах JSPerf найдены здесь . И тесты jsben.ch находятся здесь . Как видите, есть заметная разница, когда их не должно быть. Если вы действительно фанат производительности, как я, то, возможно, вам стоит попытаться уменьшить количество переменных и функций в области и, в частности, устранить полиморфизм (например, использовать одну и ту же переменную для хранения двух разных типов).

  1. Изменчивость изменчивости

Когда вы используете varключевое слово для объявления переменной, вы можете переназначить другое значение этой переменной следующим образом.

(function(){
    "use strict";
    var foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

Однако когда мы используем оператор const, ссылка на переменную становится неизменной. Это означает, что мы не можем присвоить новое значение переменной. Обратите внимание, однако, что это не делает содержимое переменной неизменным: если вы это сделаете const arr = [], вы все равно можете это сделать arr[10] = "example". Только делать что-то вроде arr = "new value"или arr = []будет выдавать ошибку, как показано ниже.

(function(){
    "use strict";
    const foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

Интересно, что если мы объявим переменную как function funcName(){}, то неизменность переменной будет такой же, как и при объявлении переменной var.

(function(){
    "use strict";
    function foobar(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

Что такое «Ближайший блок»

«Ближайший блок» является ближайшей «функцией» (включая асинхронные функции, функции генератора и асинхронные функции генератора). Тем не менее, что интересно, a function functionName() {}ведет себя как var functionName = function() {}когда находится в незамкнутом блоке к элементам за пределами указанного замыкания. Обратите внимание.

  • Нормальный var add=function(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}');
  }
} catch(e) {
  console.log("Is a block");
}
var add=function(a, b){return a + b}

  • Нормальный function add(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
function add(a, b){
  return a + b;
}

  • функция

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(function () {
    function add(a, b){
      return a + b;
    }
})();

  • Заявление (такой , как if, else, for, while, try/ catch/ finally, switch, do/ while, with)

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
{
    function add(a, b){
      return a + b;
    }
}

  • Функция стрелки с var add=function()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    var add=function(a, b){
      return a + b;
    }
})();

  • Функция стрелки с function add()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    function add(a, b){
      return a + b;
    }
})();

20
7.03.2020 15:42:53