In JavaScript, what is the advantage of !function(

2019-01-16 02:35发布

问题:

Possible Duplicate:
What does the exclamation mark do before the function?

I've long used the following for self-executing, anonymous functions in JavaScript:

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

Lately, I've started seeing more instances of the following pattern (e.g., in Bootstrap):

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

Anyone know what the advantage is of the second pattern? Or, is it just a stylistic preference?

回答1:

These two different techniques have a functional difference as well as a difference in appearance. The potential advantages of one technique over the other will be due to these differences.

Concision

Javascript is a language where concision can be very important, because Javascript is downloaded when the page loads. That means that the more concise the Javascript, the faster the download time. For this reason, there are Javascript minifiers and obfuscators that compress the Javascript files to optimize the download time. For example, the spaces in alert ( "Hi" ) ; would be optimized to alert("Hi");.

Keeping this in mind, compare these two patterns

  • Normal closure:   (function(){})() 16 characters
  • Negated closure: !function(){}() 15 characters

This is a micro-optimization at best, so I don't find this a particularly compelling argument unless you are doing a code golf contest.

Negating the returned value

Compare the result value of a and b.

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

Since the a function does not return anything, a will be undefined. Since the negation of undefined is true, b will evaluate to true. This is an advantage to people who either want to negate the returned value of the function or have an everything-must-return-a-non-null-or-undefined-value fetish. You can see an explanation for how this works on this other Stack Overflow question.

I hope that this helps you understand the rationale behind this function declaration that would typically be considered an anti-pattern.



回答2:

I always fall back on Ben Alman's IIFE piece for questions like this. It's the definitive as far as I'm concerned.

Here's the meat of the article:

// Either of the following two patterns can be used to immediately invoke
// a function expression, utilizing the function's 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's 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:

It seems that the key thing is that you're basically keeping the parser from interpreting the function as a function declaration, and instead it's being interpreted as an anonymous function expression.

Using the parens to group the expression or using the ! to negate the return are both just techniques of changing the parsing. It's then immediately invoked by the following parens. Any and all of these forms are having the same net effect in that regard, assuming no explicit return value:

(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

If you're not capturing the returned value, there's no significant difference. One could argue that the ~ might be a faster op since it's just flipping bits, or maybe ! is a faster op since it's a true/false check and returning the negation.

At the end of the day though, the way most people are using this pattern is that they're trying to break off a new level of scope to keep things clean. Any and all work. The latter forms are popular because while they do introduce an additional (typically unnecessary) operation, saving every extra byte helps.

Ben Alman has a fantastic writeup on the topic: http://benalman.com/news/2010/11/immediately-invoked-function-expression/



回答4:

The first "pattern" calls the anonymous function (and has the result of its return value) while the second calls the anonymous function and negates its result.

Is that what you're asking? They do not do the same thing.



回答5:

It is almost only stylistic preference, except for the fact that ! provides a function return (i.e. returns true, which comes from !undefined).

Also, it's one fewer character.



回答6:

Well in the first case you are using ( ) to wrap the object you want to execute with the next set of (), and in the next case you are using operator that takes one argument (negation operator !) and you are making it implicitly wrap its argument (funcion) with ( ) so you actually get !(function () { })(), execute the function, and negate the result it returns. This can also work with -, +, ~ in the same principle since all those operators take one argument.

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

Why would you want to do this? I guess it is a personal preference or if you have big .JS and want to save 1 char per anonymous function call... :D