Расположение скобок для автоматического выполнения функций анонимного JavaScript?

Недавно я сравнивал текущую версию json2.js с версией, имевшейся в моем проекте, и заметил разницу в том, как выражение функции был создан и сам выполнен.

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

(function () {
  // code here
})();

но теперь он завершает функцию автозапуска в скобках.

(function () {
  // code here
}());

В принятом ответе комментария к CMS в комментариях Объяснить JavaScripts инкапсулированный анонимный синтаксис, что "оба: (function(){})(); и (function(){}()); действительны."

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

Ответ 1

Они практически одинаковы.

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

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

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

> function(){}()
SyntaxError: Unexpected token (
> (function(){})()
undefined
> (function(){return 'foo'})()
"foo"
> (function(){ return 'foo'}())
"foo"

Ответ 2

В этом случае это не имеет значения. Вы вызываете выражение, которое разрешает функцию в первом определении и определяет и сразу вызывает функцию во втором примере. Они похожи, потому что выражение функции в первом примере - это просто определение функции.

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

(foo || bar)()

Ответ 3

От синтаксиса нет никакой разницы.

Относительно ваших опасений по поводу второго метода его выполнения:

Рассмотрим:

(function namedfunc () { ... }())

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

((namedfunc = function namedfunc () { ... })())

Внешние parens не нужны:

(namedfunc = function namedfunc () { ... })()

Но вы не хотели, чтобы это глобальное объявление так или иначе, не так ли?

Итак, это сводится к:

(function namedfunc () { ... })()

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

(function () { ... })()

То, что я думаю об этом (может быть, неверно, я еще не читал спецификацию ECMAScript). Надеюсь, что это поможет.

Ответ 4

Разница существует только потому, что Дугласу Крокфорду не нравится первый стиль для IIFEs! (seriuosly) Как вы можете видеть в этом видео!.

Единственная причина существования дополнительной обертки () {в обоих стилях} заключается в том, чтобы помочь сделать этот раздел кода Function Expression, потому что Function Declaration не может быть немедленно вызвана. Некоторые скрипты/минифигуры просто используют +, !, - и ~ вместо слишком круглых скобок. Вот так:

+function() {  
    var foo = 'bar';  
}();

!function() {  
    var foo = 'bar';  
}();

-function() {  
    var foo = 'bar';  
}();

~function() {  
    var foo = 'bar';  
}();

И все это точно так же, как ваши альтернативы. Выбор среди этих случаев полностью по своему усмотрению и не имеет значения. {tе, у которых (), производят 1 байт более крупный файл;-)}