Місце дужки для автоматичного виконання анонімних функцій JavaScript?


107

Нещодавно я порівнював поточну версію json2.js з версією, яку я мав у своєму проекті, і помітив різницю в тому, як було створено і самовиконано вираз функції.

Код, який використовується для загортання анонімної функції в дужки, а потім її виконання,

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

але тепер він обгортає автоматично виконану функцію в дужках.

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

Є коментар від CMS до прийнятої відповіді в поясненому синтаксисом анонімної функції JavaScript, поясненого JavaScript, що "і те: (function(){})();і (function(){}());є дійсним".

Мені було цікаво, в чому різниця? Чи займає перший пам'ять, залишаючи навколо себе глобальну, анонімну функцію? Де повинні бути розміщені дужки?




1
Читайте також про мету цієї конструкції або перевірте ( технічне ) пояснення (також тут ). Для чого потрібні дужки, дивіться це питання .
Бергі

Відповіді:


66

Вони практично однакові.

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

Другий виконує функцію, і круглі дужки навколо автоматичного виклику роблять його дійсним виразом. Він також оцінюється до невизначеного.

Я не думаю, що існує "правильний" спосіб зробити це, оскільки результат виразу той самий.

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

8
JSLint хоче "(функція () {} ());". JSLint каже: "Перемістіть виклик у паролі, які містять функцію".
XP1

27
Насправді ви не обмежені цими двома, ви можете використовувати майже все, що змушує компілятор усвідомити, що функція є частиною виразу, а не твердженням, таким як +function(){}()або !function(){}().
Тгр

49
@ XP1: JSLint хоче багато речей, які є специфічними для стилю Крокфорда, а не бути суттєвими. Це одна з них.
TJ Crowder

@TJCrowder Що б ти порадив? jQuery використовує перший стиль, а Крокфорд використовує другий.
Teej

4
@ThorpeObazee: Це справді не має значення, тому робіть все, що завгодно. Я б рекомендував проти деяких більш відвертих ( -function(){}();, !function(){}();і в основному будь-який інший оператор раніше function, але також працював, але я б дотримувався версій з використанням паронів). Я бачу перший а набагато більше, ніж другий, і це моє уподобання; це має більше сенсу і для мене, але це суб'єктивно. FWIW: jsbin.com/ejaqow
TJ Crowder

13

У цьому випадку це не має значення. Ви викликаєте вираз, який вирішує функцію в першому визначенні, а в другому прикладі визначаєте та негайно викликаєте функцію. Вони схожі, тому що вираз функції в першому прикладі є лише визначенням функції.

Є й інші, очевидно, корисні випадки для виклику виразів, які вирішують функції:

(foo || bar)()

3
Для пояснення іншим читачам (головним чином тому, що я сам спочатку цього не зрозумів :)) foo та / або смуга повинні вже дорівнювати деякій функції. (напр foo = function(){alert('hi');}., якщо жодна з них не є функцією, викидається помилка.
Олександр Птах

3
@AlexanderBird Подальше уточнення - воно також призведе до помилки, якщо вона fooє "truthy", але не є функцією.
JLRishe

9

Немає жодної різниці поза синтаксисом.

Щодо ваших занепокоєнь щодо другого способу його виконання:

Поміркуйте:

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

namedfuncвсе ще не буде в глобальному масштабі, навіть якщо ви вказали ім'я. Те саме стосується і анонімних функцій. Єдиний спосіб отримати його в такому обсязі - присвоїти йому змінну всередині паронів.

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

Зовнішні парени не потрібні:

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

Але ви все одно не хотіли цієї глобальної декларації, чи не так?

Тож воно зводиться до:

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

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

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

Ось так я думаю про це (можливо, неправильно, я ще не читав специфікацію ECMAScript). Сподіваюся, це допомагає.


Зауважте, що arguments.calleeце застаріло з ES5 (і заборонено в суворому режимі).
nyuszika7h

"Зовнішні паролі не потрібні:" - Я думаю, вони запобігають помилкам, коли файли об'єднані, інакше вам знадобиться! або щось.
Jimmyt1988

-3

Різниця існує лише тому, що Дугласу Крокфорду не подобається перший стиль для IIFE ! (seriuosly) Як ви можете побачити у цьому відео !!.

Єдина причина існування додаткової упаковки (){в обох стилях} - це допомогти зробити цей розділ коду Function Expression , оскільки Декларація функції не може бути негайно викликана. Деякі скрипти / применшувати-ERS просто використовувати +, !, -і ~замість того, щоб занадто круглі дужки. Подобається це:

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

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

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

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

І все це точно так само, як і ваші альтернативи. Вибір серед цих випадків відбувається самостійно, і це не має ніякого значення. {Ті, що ()створюють файл на 1 байт ;-)}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.