функция JavaScript, ведущая взрыва! синтаксис


204

Я видел этот синтаксис в нескольких библиотеках сейчас, и мне интересно, какова выгода. (заметьте, я хорошо осведомлен о замыканиях и о том, что делает код, меня интересуют только синтаксические различия)

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

Как альтернатива более распространенным

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

для самостоятельного вызова анонимных функций.

Мне интересно несколько вещей. Прежде всего, что позволяет верхнему примеру на самом деле работать? Почему взрыв необходим для того, чтобы сделать это утверждение синтаксически правильным? Мне также сказали, что это +работает, и я уверен, что некоторые другие, вместо!

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

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


Фреймворки любят сохранять как можно больше символов, которые минимизатор не может оптимизировать.
Алекс

Первое преимущество, которое приходит мне в голову, это то, что вы можете создать песочницу, например, (function ($) {...}) (jQuery);
Дж. С. Тейлор

2
оба примера достигают этого. Как уже упоминалось, я понимаю, что делают эти функции, меня больше интересуют синтаксические различия
Брэд,

8
Я связываю это с необходимостью быть милой таким изощренным способом, как предыдущая команда. «О, те язычники в скобках, у нас есть !!»
Джаред Фарриш

2
Я никогда не знал об этом, круто. Мне нравится, !поскольку это подчеркивает, что это выполняется.
cdmckay

Ответы:


97

В идеале вы должны быть в состоянии сделать все это просто так:

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

Это означает объявить анонимную функцию и выполнить ее. Но это не сработает из-за особенностей грамматики JS.

Таким образом, кратчайшая форма достижения этого заключается в использовании некоторого выражения, например 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
}();

не подходит , что форма (и вызовет синтаксическую ошибку на первое открытие Paren , потому что нет никакого имени функции), поэтому скобки используются для очерчивания анонимной функции выражения .

(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-файлах вам не нужно беспокоиться, если в предыдущем коде отсутствуют точки с запятой. Так что нет необходимости в общем; (function () {}) (); чтобы убедиться, что ваш собственный не сломается.

Я знаю, что мой ответ немного поздно, но я думаю, что он еще не был упомянут :)


6
+1 за отзыв и воспоминания ... никто не любит писать javascript без точек с запятой в наши дни.
Пабло Гризафи

4
Twitter Bootstrap - это все JS без точек с запятой, и это довольно ново ... (извините, если приведенный выше комментарий носил саркастический характер, и я его пропустил).
brandwaffle

2
Это не совсем так. Рассмотрим следующий пример:! Function () {console.log ("ham");} ()! Function () {console.log ("cheese")} (); появляется сообщение об ошибке: «SyntaxError: неожиданный токен!»
тяжеловес

Да ты прав. Там есть ошибка, если вы поместите их в одну строку. Я не думал об этом. Но никакой сценарий объединения / lib, который я использовал до сих пор, не делает этого. И когда вы минимизируете & concat ваши файлы добавляются точки с запятой. Так что, честно говоря, я не могу представить, чтобы вы столкнулись с этой проблемой. С другой стороны, сейчас 2 часа ночи, и я могу быть в неведении :)
Smoe

6

С одной стороны, jsPerf показывает, что использование !(UnaryExpression's) обычно быстрее. Иногда они оказываются равными, но когда они не равны, я не видел безударных победу над другими: http://jsperf.com/bang-function

Это было протестировано на последней версии Ubuntu с самой старой (скажем ..) версией Chrome 8. Поэтому результаты могут отличаться, конечно.

Редактировать: Как насчет чего-то вроде сумасшедшего delete?

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

или void?

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

интересный! Я получил около 50/50, хотя в Safari по скорости, без ударов, безусловно, выдержал. Интересно, есть ли какая-то теория возможных различий в скорости?
Брэд

@brad Должно быть что-то связанное с сафари, если вы посмотрите на тесты, большинство других браузеров, кажется, одобряют !. Но я также хотел бы найти теорию об этом :)
Shaz

3
Мне нравится void, потому что он явно говорит: «Меня не волнует возвращаемое значение», и потому, что он напоминает мне о соглашениях на других языках
code_monk

4

Как вы можете видеть здесь , лучший способ сделать самозванный метод в javascript - это использовать:

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

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

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

1
Я сомневаюсь, что производительность - причина использовать тот или иной синтаксис. При скорости 70M операций в секунду объявление закрытия будет в тысячи раз быстрее, чем код внутри
Eloims

3

Итак, с отрицанием "!" и все другие унарные операторы, такие как +, -, ~, delete, void, много сказано, просто для подведения итогов:

!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.