Що робить знак оклику перед функцією?


1242
!function () {}();

4
@Dykam Його корисність пояснюється в цій відповіді: stackoverflow.com/questions/5422585 / ...
hectorct


1
Ми називаємо це
самовиконанням

7
@befzz Краще позначати це виразом негайно викликаних функцій, як ця стаття пізніше пояснює ("самовиконання" передбачає рекурсію)
Zach Esposito

Відповіді:


2117

Синтаксис JavaScript 101. Ось декларація функції :

function foo() {}

Зверніть увагу , що немає точки з коми: це просто функція декларації . Вам потрібна виклик foo(), щоб фактично запустити функцію.

Тепер, коли ми додаємо, здавалося б, нешкідливий знак оклику: !function foo() {}це перетворює це на вираз . Тепер це вираження функції .

!У поодинці не викликає функцію, звичайно, але тепер ми можемо поставити ()в кінці: !function foo() {}()який має більш високий пріоритет , ніж !та миттєво викликає функцію.

Отже, що робить автор - це збереження байта на вираз функції; більш читаним способом написання було б таке:

(function(){})();

Нарешті, !робить вираз поверненням істинним. Це тому, що за замовчуванням все повернення IIFE undefined, яке залишає нас з !undefinedякими є true. Не особливо корисно.


229
+1. Це справді найкраща відповідь тут, і, на жаль, навряд чи заперечується. Очевидно, що !повертається булевим, ми всі це знаємо, але головне, що ви робите, це те, що він також перетворює оператор декларації функції у вираз функції, щоб функцію можна було негайно викликати, не загортаючи її в дужки. Не очевидний, і чітко наміри кодера.
gilly3

64
+1 Це єдина відповідь, яка насправді стосується ЧОМУ ви б хотіли це зробити, і чому людина бачить, що вона використовується більше, ніж заперечення результату повернення, здавалося б, вимагає. Одинарний оператор! (також ~, - і +) від'єднує від оголошення функції і дозволяє паренам у кінці () викликати функцію на місці. Це часто робиться для створення локального простору / простору імен для змінних при написанні модульного коду.
Том Ожер

65
Ще одна користь - це! спричиняє вставку напівкрапки, тому неможливо, щоб ця версія була неправильно поєднана з файлом, який не закінчується символом a. Якщо у вас є форма (), вона вважатиме викликом функції все, що було визначено в попередньому файлі. Наконечник капелюха моєму співробітникові.
Юре Триглав

5
@Carnix var foo =порушує неоднозначність тверджень / виразів, і ви можете просто написати var foo = function(bar){}("baz");тощо.
Ніл

6
Зазвичай це робиться за допомогою сценаріїв мінімізації / уліфікації, де кожен байт рахується.
Діма Слівін

367

Функція:

function () {}

не повертає нічого (або невизначено).

Іноді ми хочемо викликати функцію правильно під час її створення. Можливо, ви б спробували спробувати це:

function () {}()

але це призводить до а SyntaxError.

Використання !оператора перед функцією спричиняє його трактування як вираз, тому ми можемо його назвати:

!function () {}()

Це також поверне булеву протилежність зворотному значенню функції, в цьому випадку true, тому що !undefinedє true. Якщо ви хочете, щоб фактичне значення повернення було результатом дзвінка, то спробуйте це зробити так:

(function () {})()

28
кому може це знадобитися?
Андрій

13
це єдина відповідь, яка пояснює випадок у запитанні, браво!
Андрій

14
Ваш другий зразок коду недійсний JavaScript. Мета цього !- перетворити декларацію функції на вираз функції, ось і все.
Skilldrick

8
@Andrey Twitter twitter використовує це у всіх файлах плагінів javascript (jQuery). Додавання цього коментаря про всяк випадок, якщо у інших може виникнути те саме питання.
Anmol Saraf

2
d3.js також використовує !functionсинтаксис
Крістіан

65

Існує хороший момент використання !для виклику функції, позначеного в посібнику JavaScript airbnb

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

!function abc(){}();
!function bca(){}();

Працюватиме так само, як

!function abc(){}();
(function bca(){})();

але зберігає один персонаж і довільно виглядає краще.

І до речі , будь-який з +, -, ~, voidоператори мають той же ефект, з точки зору виклику функції, звичайно , якщо ви повинні використовувати що - то , щоб повернутися з цієї функції вони будуть діяти по- іншому.

abcval = !function abc(){return true;}() // abcval equals false
bcaval = +function bca(){return true;}() // bcaval equals 1
zyxval = -function zyx(){return true;}() // zyxval equals -1
xyzval = ~function xyz(){return true;}() // your guess?

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

!function abc(/*no returns*/) {}()
+function bca() {/*no returns*/}()

Зробить безпечне виконання коду, як і перший зразок коду.

Ця помилка призведе до того, що JavaScript ASI не зможе виконати свою роботу.

!function abc(/*no returns*/) {}()
(function bca() {/*no returns*/})()

Одне зауваження щодо операторів-одинаків, вони б виконували подібну роботу, але лише у випадку, якщо вони не використовувались у першому модулі. Тож вони не такі безпечні, якщо ви не маєте тотального контролю за порядком конкатенації.

Це працює:

!function abc(/*no returns*/) {}()
^function bca() {/*no returns*/}()

Це не:

^function abc(/*no returns*/) {}()
!function bca() {/*no returns*/}()

3
Насправді ці інші символи не мають такого ж ефекту. Так, вони дозволяють викликати функцію, як описано, але вони не тотожні. Поміркуйте: var foo =! Function (bar) {console.debug (bar); } ("кажан"); Незалежно від того, який із ваших символів ви поставите спереду, ви отримуєте "кажан" у своїй консолі. Тепер додайте console.debug ("foo:", foo); - ви отримуєте дуже різні результати залежно від того, який символ ви використовуєте. ! примушує повернути значення, яке не завжди бажано. Я віддаю перевагу синтаксису ({}) () для ясності та точності.
Carnix

29

Він повертає, чи може вислів оцінювати значення false. наприклад:

!false      // true
!true       // false
!isValid()  // is not valid

Ви можете використовувати його двічі, щоб примусити значення до булевого значення:

!!1    // true
!!0    // false

Отже, щоб більш безпосередньо відповісти на ваше запитання:

var myVar = !function(){ return false; }();  // myVar contains true

Редагувати: це побічний ефект від зміни декларації функції на вираз функції. Наприклад, наступний код недійсний, оскільки він інтерпретується як декларація функції, у якій відсутній необхідний ідентифікатор (або ім'я функції ):

function () { return false; }();  // syntax error

6
Для ясності для читачів, які, можливо, захочуть використовувати завдання з функцією, що негайно викликається, ваш приклад код var myVar = !function(){ return false; }()може опустити !подібне, var myVar = function(){ return false; }()і функція буде виконуватись правильно, а значення, що повертається, буде недоторканим.
Марк Фокс

1
Щоб було зрозуміло, ви можете використовувати його один раз для примушування до булевого, тому що це логічно не оператор. ! 0 = вірно, і! 1 = хибно. Для мінімізації JavaScript ви хочете замінити trueна !0і falseна !1. Це економить 2 або 3 символи.
Трайнко

9

Його просто зберегти байт даних, коли ми робимо мінімізацію JavaScript.

розглянемо нижче анонімну функцію

function (){}

Щоб зробити вищезгадане як функцію самозакликання, ми, як правило, змінимо вищевказаний код як

(function (){}())

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

!function (){}()

І все одно, обидва є самостійними функціями, і ми також зберігаємо байт. Замість двох символів (,)ми просто використали один символ!


1
Це корисно, оскільки часто ви побачите це у мінімізованому js
Для Імені

5

! є логічним НЕ оператором, це бульний оператор, який переверне щось на протилежне.

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

Замість цього використовуйте дужки, що закриваються, і BANG ( ! ), Якщо потрібно.

// I'm going to leave the closing () in all examples as invoking the function with just ! and () takes away from what's happening.

(function(){ return false; }());
=> false

!(function(){ return false; }());
=> true

!!(function(){ return false; }());
=> false

!!!(function(){ return false; }());
=> true

Інші оператори, які працюють ...

+(function(){ return false; }());
=> 0

-(function(){ return false; }());
=> -0

~(function(){ return false; }());
=> -1

Комбіновані оператори ...

+!(function(){ return false; }());
=> 1

-!(function(){ return false; }());
=> -1

!+(function(){ return false; }());
=> true

!-(function(){ return false; }());
=> true

~!(function(){ return false; }());
=> -2

~!!(function(){ return false; }());
=> -1

+~(function(){ return false; }());
+> -1

5

Знак оклику змушує будь-яку функцію завжди повертати булеве значення.
Кінцеве значення - це заперечення значення, повернене функцією.

!function bool() { return false; }() // true
!function bool() { return true; }() // false

Опущення !в наведених прикладах було б SyntaxError .

function bool() { return true; }() // SyntaxError

Однак кращим способом досягти цього було б:

(function bool() { return true; })() // true

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

3

Це ще один спосіб написання IIFE (негайно викликається вираз функції).

Інший її спосіб написання -

(function( args ) {})()

такий же, як

!function ( args ) {}();

Ну, це не зовсім так; 2-а форма заперечує результат виклику функції (а потім відкидає її, оскільки немає присвоєння значення). Я строго віддаю перевагу більш чіткому (function (args) {...})()синтаксису і залишаю цю !functionформу інструментам для мінімізації та обфускування.
Тобіас

-1

! заперечує (навпаки) все, що ви очікуєте в результаті, тобто якщо у вас є

var boy = true;
undefined
boy
true
!boy
false

коли ви телефонуєте boy, ваш результат буде true, але в момент, коли ви додасте, !коли дзвонить boy, тобто !boyваш результат буде false. Інакше кажучи, ви маєте на увазі NotBoy , але на цей раз це в основному бульний результат, trueабо false.

Це те саме, що відбувається з !function () {}();виразом, запуску лише function () {}();позначить вам помилку, але додавання !прямо перед вашим function () {}();виразом, робить це протилежним тому, function () {}();яке повинно вас повернути true. Приклад можна побачити нижче:

function () {}();
SyntaxError: function statement requires a name
!function () {}();
true
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.