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

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

Два способа:

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

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

7102
Richard Garside 3 Дек 2008 в 14:31

24 ответа

Лучший ответ

Различие состоит в том, что functionOne является выражением функции и поэтому определяется только при достижении этой строки, тогда как functionTwo является объявлением функции и определяется, как только выполняется его окружающая функция или сценарий (из-за < a href = "http://adripofjavascript.com/blog/drips/variable-and-function-hoisting.html" rel = "noreferrer"> подъем ).

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

// 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 действует, в этом случае просто возникает ошибка.

4991
Sid Vishnoi 15 Май 2018 в 09:03

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

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

}

Или

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

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

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

62
Community 23 Май 2017 в 11:55

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

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

var foo = function foo() {};

Оператор функции:

function foo() {};

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

Так

function foo() {};

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

var foo = function foo() {};

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

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

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

Screenshot from video

24
Community 23 Май 2017 в 12:18

Первый (функция 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
Peter Mortensen 28 Дек 2015 в 20:29

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

С участием

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

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

В то время как

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

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

76
Alireza 29 Июн 2017 в 14:08

Сначала я хочу исправить Грега: 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() - ответ таков: это зависит от браузера.

1930
Merlin 10 Окт 2016 в 20:38

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

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

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

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

{
    member:function() { /* How do I make "this.member" a named function? */
    }
}
30
Peter Mortensen 28 Дек 2015 в 19:44

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

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

secondFunction()
6
SuperNova 10 Май 2016 в 07:05

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

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

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

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

    return exports;
})();

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

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

91
ROMANIA_engineer 19 Окт 2014 в 22:24

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

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

enter image description here

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

40
Leon Gaban 1 Май 2015 в 15:06

Они очень похожи с некоторыми небольшими отличиями: первая - это переменная, назначенная анонимной функции (объявление функции), а вторая - нормальный способ создания функции в 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
Alireza 30 Июл 2017 в 04:30

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

7
Peter Mortensen 28 Дек 2015 в 20:32

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

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

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

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

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

Кроме того, незадекларированные назначения создают ReferenceError в ECMAScript 5 в строгий режим .

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

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

142
Community 23 Май 2017 в 12:10

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

Однако есть разница в как и когда объект функции фактически связан с его переменной. Это различие связано с механизмом подъема переменной в 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 не играет никакой роли и остается нетронутым.

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
eljenso 6 Фев 2013 в 16:29

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

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

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

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

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

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

functionOne();
function functionOne() {
   // Some code
}
10
Peter Mortensen 28 Дек 2015 в 20:42

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

function abc(){}

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

var abc = function() {};

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

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

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

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

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

32
sla55er 9 Май 2015 в 09:37

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

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

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

Chrome 62.0.3202 Chrome test

FireFox 55 Тест Firefox

Chrome Canary 63.0.3225 Chrome Canary test


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


< Сильный > < EM> Firefox Firefox named_anonymous Chrome Canary Chrome Canary named_anonymous < Сильный > < EM> Chrome Chrome named_anonymous

10
Panos Kal. 28 Сен 2017 в 05:13

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

Примеры из учебника: рекурсивные вызовы в 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
Community 23 Май 2017 в 12:34

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

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
Community 23 Май 2017 в 12:26

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

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
Pawel Furmaniak 25 Окт 2013 в 16:38

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

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

25
ROMANIA_engineer 19 Окт 2014 в 22:25

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

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

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

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

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

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

25
Peter Mortensen 28 Дек 2015 в 20:26

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

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
Ingo Kegel 17 Янв 2013 в 08:48

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

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

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

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

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

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

Жгут (Fiddle)

'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
Jackson 13 Янв 2015 в 03:24