JavaScript Bang "!" Функции против ведущего полуколона ";" IIFEs

Airbnd предлагает Я делаю это:

!function() {
  // ...
}();

Потому что:

Это гарантирует, что если отклоненный модуль забудет включить окончательный точки с запятой не возникают ошибки при создании скриптов сцепляются.

Взлом позволяет мне работать над языковыми правилами грамматики:

// Evaluated in Chromium 34 console.
function(){}(); // => SyntaxError: Unexpected token (
!function(){}(); // => true

И при конкатенации других модулей, кажется, удача делает трюк:

!function(){}();function(){}(); // => SyntaxError: Unexpected token (
!function(){}();!function(){}(); // => true
(function(){}());!function(){}(); // => true

Однако на самом деле это не является "безопасным", потому что если у кого-то еще нет двоеточия в конце его script:

!function(){}()!function(){}(); // => SyntaxError: Unexpected token !
(function(){}())!function(){}(); // => SyntaxError: Unexpected token !

Похоже, что лучше всего использовать IIFE с двумя полутонами.

;(function() {
  // ...
}());

!function(){}();(function(){}()); // => undefined
(function(){}());(function(){}()); // => undefined
!function(){}();;(function(){}()); // => undefined
(function(){}());;(function(){}()); // => undefined

Я что-то упустил? Действительно ли это приемлемо для использования взрыва "!" функции или ведущие полуколония ";" IIFE действительно превосходят из-за того, как они конкатенируются?

Ответ 1

У вас всегда есть IEFE. Если вы заключите их в круглые скобки или префикс их с помощью !, это ваш выбор и не имеет значения. Вам нужно либо одно, чтобы заставить функцию анализироваться как выражение. См. javascript function leading bang! синтаксис для деталей.

Если вы префикс всей конструкции с помощью ;, чтобы предотвратить конкатенацию ошибок с плохо написанными сценариями (Что делает лидирующая точка с запятой в библиотеках JavaScript?) полностью не связан. Вы можете смешивать шаблоны по своему усмотрению:

 !function(){…}() // not safe for arbitrary concatenation
 (function(){…}()) // not safe for arbitrary concatenation either
;!function(){…}()
;(function(){…}())

Однако существует один случай конкатенации, где () vs ! делает разницу: если два сценария объединены, так что между ними есть новая строка, а первая не заканчивается точкой с запятой. Это позволяет автоматическую точку с запятой прыгать - когда следующая строка начинается с взрыва!

1 + 2             // script A
!function(){…}(); // script B
// works!

1 + 2              // script A
(function(){…}()); // script B
// runtime error: "2 is not a function" (or whatever the previous line ends in)

Мы узнаем: всегда заканчивайте script точкой с запятой. Используйте интеллектуальную конкатенацию. Запустите script точкой с запятой, если вам нужно быть в безопасности от немой конкатенации.

Ответ 2

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

Ведущая точка с запятой, с другой стороны, заканчивает любое выражение "открытого" выражения, которое может появиться перед ним.

Но если вы следуете объяснению, кажется, что ! хватит, если это первый символ в строке. По-видимому, JS добавит точку с запятой к предыдущей из-за ASI. Однако это, по-видимому, более хрупкий подход, поскольку вы не можете полностью контролировать, как модули конкатенируются. Использование точки с запятой определенно "безопаснее".

Ответ 3

На самом деле это тоже работает:

;!function() {
  // ...
}();

!function(){}()!function(){}(); // => SyntaxError: Unexpected token !
!function(){}();!function(){}(); // => true
(function(){}());!function(){}(); // => true
!function(){}();;!function(){}(); // => true
(function(){}());;!function(){}(); // => true

Таким образом, IIFE не лучше, чем функции bang, как я рассеянно предполагал в последнем абзаце моего вопроса. Независимо от того, используете ли вы функцию bang или IIFE, ведущая полуколона перед ними является хорошей защитной техникой.