функція javascript, що провідна! синтаксис


204

Я бачив цей синтаксис у кількох бібліотеках зараз і мені цікаво, у чому користь. (зауважте, я добре знаю про закриття та те, що робить код, мене турбують лише синтаксичні відмінності)

!function(){
  // do stuff
}();

Як альтернатива більш поширеному

(function(){
  // do stuff
})();

для самостійного виклику анонімних функцій.

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

По-друге, яка користь? Все, що я можу сказати, - це економить одного персонажа, але я не можу уявити, що це така величезна користь для залучення численних усиновителів. Чи є якась інша користь, яку мені не вистачає?

Єдиною іншою відмінністю, яку я бачу, було б повернене значення функції самовикликання, але в обох цих прикладах нас дуже не хвилює повернене значення функції, оскільки воно використовується лише для створення закриття. Тож хтось може мені сказати, чому можна використовувати перший синтаксис?


Рамки люблять зберігати якомога більше символів, які мініфіксатор не може оптимізувати.
alex

Перша користь приходить мені в голову - ви можете створити пісочницю типу, (функція ($) {...}) (jQuery);
JS Taylor

2
обидва приклади цього досягають. Як уже згадувалося, я розумію, що ці функції роблять, мене більше цікавлять синтаксичні відмінності
brad

8
Я пов'язую це з необхідністю, вимогою бути симпатичним таким чином, що є більш досконалим, ніж попередній екіпаж. "О, ці батьківські погани, у нас є !!"
Джаред Фарріш

2
Я ніколи про це не знав, дивовижно. Мені подобається, !як він підкреслює, що він виконується.
cdmckay

Відповіді:


97

В ідеалі ви повинні зробити все це просто так:

function(){
  // do stuff
}(); 

Це означає оголосити анонімну функцію та виконати її. Але це не вийде через специфіку граматики ЖС.

Тому найкоротшою формою досягнення цього є використання деякого вираження, наприклад, UnaryExpression (і так CallExpression):

!function(){
  // do stuff
}(); 

Або для розваги:

-function(){
  // do stuff
}(); 

Або:

+function(){
  // do stuff
}(); 

Або навіть:

~function(){
  // do stuff
  return 0;
}( );

3
тож тоді єдина вигода терміновості?
бред

12
Я додав усі варіанти вище до тесту на працездатність за адресою: jsperf.com/bang-function
Shaz

5
Я б сказав, виразність. Швидкість насправді не має значення в таких випадках, як вона працює один раз.
c-smile

1
З цікавості я помітив, що жоден удар і удар не виконуються найшвидше, але десь в еволюції Chrome принаймні, удар став швидшим, ніж ніякий удар. (Мабуть, статистично незначний, але ...) Чи є причина? Я мало знаю про код під капотом, але вважаю його досить захоплюючим.
jmk2142

Два ваших одинарних оператора можуть бути інтерпретовані як двійкові, якщо крапка з комою відсутня. Перший і останній є найбезпечнішими з цих прикладів.

73

У Javascript functionочікується , що рядок, що починається з, є функцією оператора і повинен виглядати так

function doSomething() {
}

Функція самовикликання, як

function(){
  // do stuff
}();

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

(function(){
  // do stuff
})();

Але все, що створює вираз (на відміну від заяви про функцію), зробить, отже, і те ! . Це говорить перекладачеві, що це не твердження функції. Крім цього, пріоритет оператора диктує, що функція викликається перед запереченням.

Я не знав про цю конвенцію, але якщо вона стане загальною, це може сприяти читанню. Я маю на увазі те, що кожен, хто читає !functionверхній частині великого блоку коду, очікуватиме самозвання, як ми, як насправді, очікують того самого, коли бачимо (function. За винятком того, що ми втратимо ці дратівливі дужки. Я б очікував, що це причина, на відміну від економії швидкості чи кількості персонажів.


Цей "рядок, що починається з функції, очікується ..." виглядає досить нечітко. Що з цього приводу:var foo = {CR/LF here} function bar() {}
c-smile

45

Крім речей, про які вже говорилося, синтаксис із! корисно, якщо ви пишете javascript без крапки з комою:

var i = 1
!function(){
  console.log('ham')
}()

i = 2
(function(){
  console.log('cheese')
})()

Перший приклад виводить "ham" як очікувалося, але другий видасть помилку, оскільки оператор i = 2 не припиняється через наступні дужки.

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

Я знаю, що моя відповідь пізно, але я думаю, що це ще не було згадано :)


6
+1 для підказки та спогадів ... ніхто не любить писати JavaScript без крапки з комою в ці дні.
Пабло Грисафі

4
Twitter Bootstrap - все JS без крапки з комою, і це зовсім нове ... (вибачте, якщо вищевказаний коментар був саркастичним за своєю суттю, і я його пропустив).
brandwaffle

2
Це насправді не так. Розглянемо наступний приклад:! Function () {console.log ("шинка");} ()! Function () {console.log ("сир")} (); ви отримуєте помилку: "SyntaxError: Несподіваний маркер!"
Heavysixer

Так, ти маєш рацію. Виникла помилка, якщо ви поставите їх у той самий рядок. Я про це не думав. Але жоден сценарій зв'язання / lib, який я раніше використовував, не робить цього. І коли ви мінімізуєте та стискаєте ваші файли, додаються крапки з комою. Тож, чесно кажучи, я не можу уявити випадок, коли ти зіткнувся з цією проблемою. З іншого боку, тут 2 ранку, і я можу бути невідомим :)
Smoe

6

З одного боку, jsPerf показує, що використання !(UnaryExpression) зазвичай швидше. Іноді вони виявляються рівними, але коли їх немає, я ще не бачив, щоб не торкнувся одного тріумфу надто багато над іншими: http://jsperf.com/bang-function

Це було перевірено на останньому Ubuntu з найстарішим (скажімо ..) Chrome, версія 8. Тому результати можуть, звичайно, відрізнятися.

Редагувати: Як щодо чогось божевільного delete?

delete function() {
   alert("Hi!"); 
}();

або void?

void function() {
   alert("Hi!"); 
}();

цікаво! Я отримав приблизно 50/50, хоча в Safari швидкість, не збита, безумовно, тримала своє. Цікаво, чи існує якась теорія щодо потенційних різниць швидкості?
бред

@brad Повинен бути щось спільне з сафарі, якщо ви подивитесь на тести, більшість інших браузерів, здається, надають перевагу !. Але я також хотів би знайти теорію щодо цього :)
Shaz

3
мені подобається недійсність, тому що прямо написано "мені не байдуже значення повернення", і тому, що це нагадує мені конвенції іншими мовами
code_monk

4

Як ви бачите тут , найкращим способом зробити самовикликані методи в JavaScript - це:

(function(){}()); -> 76,827,475 ops/sec

!function(){}();  -> 69,699,155 ops/sec

(function(){})(); -> 69,564,370 ops/sec

1
Сумніваюся, продуктивність є причиною використання одного чи іншого синтаксису. При швидкості 70 м / сек заявлення про закриття буде в тисячі разів швидше, ніж код всередині
Елоімз,

3

Отже, з негативом "!" та всі інші одинарні оператори, такі як +, -, ~, delete, недійсні, було сказано багато, лише підсумовуючи:

!function(){
  alert("Hi!");
}(); 

Або

void function(){
  alert("Hi!");
}();

Або

delete function(){
  alert("Hi!");
}();

І ще кілька випадків із бінарними операторами для задоволення :)

1 > function() {
   alert("Hi!"); 
}();

Або

1 * function() {
   alert("Hi!"); 
}();

Або

1 >>> function() {
   alert("Hi!"); 
}();

Або навіть

1 == function() {
   alert("Hi!"); 
}();

Залишаючи термінал для когось іншого хлопця :)


12
0?0:function() { alert("Hi!"); }();
daniel1426

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