В JavaScript, в чем преимущество функции function() {}() over (function() {})()?

Возможный дубликат:
Что делает восклицательный знак перед функцией?

Я уже давно использовал следующие функции для самостоятельного выполнения анонимных функций в JavaScript:

(function () { /* magic happens */ })()

В последнее время я начал видеть больше экземпляров следующего шаблона (например, в Bootstrap):

!function () { /* presumably the same magic happens */ }()

Кто-нибудь знает, какое преимущество имеет второй шаблон? Или, это просто стилистические предпочтения?

Ответ 1

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

краткость

Javascript - это язык, на котором concision может быть очень важным, потому что Javascript загружается при загрузке страницы. Это означает, что чем короче Javascript, тем быстрее время загрузки. По этой причине есть Javascript minifiers и obfuscators, которые сжимают файлы Javascript для оптимизации времени загрузки. Например, пробелы в alert ( "Hi" ) ; будут оптимизированы для alert("Hi");.

Помня об этом, сравните эти два шаблона

В лучшем случае это микро-оптимизация, поэтому я не считаю это особенно убедительным аргументом, если вы не делаете code golf конкурс.

Отрицание возвращаемого значения

Сравните значение результата a и b.

var a = (function(){})()
var b = !function(){}()

Так как функция a ничего не возвращает, a будет undefined. Поскольку отрицание undefined равно true, b будет оцениваться до true. Это преимущество для людей, которые либо хотят отрицать возвращаемое значение функции, либо иметь фетиш-значение all-must-return-a-non-null-or- undefined. Вы можете увидеть объяснение того, как это работает в этом другом вопросе.

Я надеюсь, что это поможет вам понять обоснование этой декларации функции, которая обычно рассматривается как анти-шаблон.

Ответ 2

Я всегда возвращаюсь на статью Бен Альмана IIFE для таких вопросов. Это окончательно, насколько мне известно.

Здесь мясо статья:

// Either of the following two patterns can be used to immediately invoke
// a function expression, utilizing the function execution context to
// create "privacy."

(function(){ /* code */ }()); // Crockford recommends this one
(function(){ /* code */ })(); // But this one works just as well

// Because the point of the parens or coercing operators is to disambiguate
// between function expressions and function declarations, they can be
// omitted when the parser already expects an expression (but please see the
// "important note" below).

var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();

// If you don't care about the return value, or the possibility of making
// your code slightly harder to read, you can save a byte by just prefixing
// the function with a unary operator.

!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();

// Here another variation, from @kuvos - I'm not sure of the performance
// implications, if any, of using the `new` keyword, but it works.
// http://twitter.com/kuvos/status/18209252090847232

new function(){ /* code */ }
new function(){ /* code */ }() // Only need parens if passing arguments

Ответ 3

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

Используя parens для группировки выражения или использования! чтобы отрицать возврат, - это просто методы изменения синтаксического анализа. Затем он сразу же вызывается следующими паранами. Любая и все эти формы имеют тот же чистый эффект в этом отношении, не предполагая явного возвращаемого значения:

(function(){ /* ... */ })(); // Arguably most common form, => undefined
(function(){ /* ... */ }()); // Crockford-approved version, => undefined
!function(){ /* ... */ }();  // Negates the return, so => true
+function(){ /* ... */ }();  // Attempts numeric conversion of undefined, => NaN
~function(){ /* ... */ }();  // Bitwise NOT, => -1

Если вы не фиксируете возвращаемое значение, существенной разницы нет. Можно утверждать, что ~ может быть более быстрым, потому что он просто переворачивает биты или, может быть! является более быстрым оператором, поскольку он проверяет истину/ложь и возвращает отрицание.

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

Бен Алман имеет фантастическую запись по теме: http://benalman.com/news/2010/11/immediately-invoked-function-expression/

Ответ 4

Первый "шаблон" вызывает анонимную функцию (и имеет результат ее возвращаемого значения), а второй вызывает анонимную функцию и отрицает ее результат.

Это то, о чем вы спрашиваете? Они не делают то же самое.

Ответ 5

Это почти стилистическое предпочтение, за исключением того, что ! предоставляет функцию return (т.е. возвращает true, которая исходит от !undefined).

Кроме того, это меньше символов.

Ответ 6

В первом случае вы используете ( ) для обертывания объекта, который вы хотите выполнить, со следующим набором (), а в следующем случае вы используете оператор, который принимает один аргумент (оператор отрицания!) и вы делаете его неявным образом заверяете свой аргумент (funcion) с помощью ( ), чтобы вы фактически получили !(function () { })(), выполнили функцию и отрицали результат, который он возвращает. Это также может работать с -, +, ~ по тому же принципу, поскольку все эти операторы принимают один аргумент.

!function () { /* presumably the same magic happens */ }()
-function () { /* presumably the same magic happens */ }()
+function () { /* presumably the same magic happens */ }()
~function () { /* presumably the same magic happens */ }()

Зачем вам это нужно? Я думаю, это личное предпочтение или если у вас большой .JS и вы хотите сохранить 1 char за анонимный вызов функции...: D