2010-08-02 10 views
96

Я недавно сравнивал текущую версию json2.js с версией, которую я имел в своем проекте, и заметил разницу в том, как было создано выражение функции и выполнено само.Расположение скобок для автоматического выполнения функций анонимного JavaScript?

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

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

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

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

Существует комментарий КМВ в принятом ответе Explain JavaScript’s encapsulated anonymous function syntax, что «как:. (function(){})();(function(){}()); и справедливы»

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

+1

См. Также [Разница между (function() {})(); и function() {}();] (http://stackoverflow.com/q/423228/1048572) и [Есть ли разница между (function() {...}()); и (function() {...})();?] (http://stackoverflow.com/q/3783007/1048572) – Bergi

+0

Связанный: [Синтаксис вызова немедленной функции] (http://stackoverflow.com/q/939386/1048572) (в JSLint) – Bergi

+1

Также читайте о [цели этой конструкции] (http://stackoverflow.com/q/592396/1048572) или проверьте ([технический] (http://stackoverflow.com/) q/4212149/1048572)) [пояснения] (http://stackoverflow.com/q/8228281/1048572) (также [здесь] (http://stackoverflow.com/a/441498/1048572)). Для чего нужны скобки, см. [Этот вопрос] (http://stackoverflow.com/q/1634268/1048572). – Bergi

ответ

59

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

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

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

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

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

JSLint хочет "(function() {}());". JSLint говорит: «Переместите вызов в параны, содержащие функцию». – XP1

+26

На самом деле вы не ограничены этими двумя, вы можете использовать практически все, что заставляет компилятор осознавать, что функция является частью выражения, а не оператора, такого как '+ function() {}()' или '! Function () {}() '. – Tgr

+45

@ XP1: JSLint хочет много вещей, которые характерны для стиля Крокфорда *, а не для существа. Это одна из них. –

13

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

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

(foo || bar)() 
+3

Для разъяснения другим читателям (главным образом потому, что я сам не понял это сначала :)), foo и/или bar должны уже равняться некоторым функция. (например, 'foo = function() {alert ('hi');}'. Если ни одна из них не является функцией, возникает ошибка. –

+2

@AlexanderBird Дальнейшее разъяснение. Также будет выдано сообщение об ошибке, если 'foo' является« правдивым » «но не функция. – JLRishe

7

Существует нет разницы за синтаксис.

Что касается ваших опасений по поводу второго способа сделать это:

Рассмотрим:

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

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

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

внешней круглые скобки не нужны:

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

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

Так что это сводится к тому:

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

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

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

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

-3

Разница просто существует, потому что Douglas Crockford не нравится первый стиль для IIFEs! (seriuosly) As you can see in this video!!.

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

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

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

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

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

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