Расположение скобок для автоматического выполнения функций анонимного 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 байт более крупный файл;-)}