question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Could this:

(function() {
  console.log('Welcome to the Internet. Please follow me.');
})();

Be this? :

// Crockford's preference - parens on the inside
(function() {
  console.log('Welcome to the Internet. Please follow me.');
}());

Issue Analytics

  • State:closed
  • Created 11 years ago
  • Comments:8 (2 by maintainers)

github_iconTop GitHub Comments

12reactions
hshoffcommented, Nov 8, 2012

If you don’t care about the return value of the IIFE, it could also be any of the following:

!function(){}();  // => true
~function(){}(); // => -1
+function(){}(); // => NaN
-function(){}();  // => NaN

Let’s explore this a bit more.

// module1.js
(function() {
  console.log('module1');
})();

// module2.js
(function() {
  console.log('module2');
})();
// production.min.js
(function(){console.log('module1');})();(function(){console.log('module2');})();
// => module1
// => module2

// crockford production.min.js
(function(){console.log('module1');}());(function(){console.log('module2');}());
// => module1
// => module2

Both work the same. It starts to get interesting when one of the modules is missing a trailing semicolon:

// problem
(function(){console.log('module1');})()(function(){console.log('module2');})();
// => module1
// => TypeError: undefined is not a function

// crockford problem
(function(){console.log('module1');}())(function(){console.log('module2');}());
// => module1
// => module2
// => TypeError: undefined is not a function

With a missing semicolon, each set of parens is trying to immediately-invoke the preceding expression. That would be the return value of the preceding IIFE.

(function(){ return undefined; })()();
// => TypeError: undefined is not a function

// equivalent
(undefined)();

(function(){ return undefined; }())(); // crockford
// => TypeError: undefined is not a function

// equivalent
(undefined());

So the difference is when the TypeError happens. Let’s check out what the arguments are up to. Note that console.log() returns undefined:

// new module1.js
(function() {
  console.log('module1');

  // return a function that logs it's
  // arguments when invoked
  return function(){
    console.log(arguments);
  };
})()
// new production.js
// unminified problem for readability
(function() {
  console.log('module1');

  // return a function that logs it's
  // arguments when invoked
  return function(){
    console.log(arguments);
  };
})()(function() {
  console.log('module2');
})();
// => module1
// => [function() {
//      console.log('module2');
//    }]
// => TypeError: undefined is not a function

// the first step is to invoke the first module
(function(){console.log('module1');return function(){console.log(arguments)};})()
// => module1

// then it invokes the return value
// with module2 as arguments
(function(){ console.log(arguments) })(function() {console.log('module2');});
// => [function() {
//      console.log('module2');
//    }]

// then it tries to invoke the return value.
// console.log returns undefined so:
(undefined)();
// => TypeError: undefined is not a function

Now let’s do that same example with the crockford way:

// new crockford module1.js
(function(){
  console.log('module1');

  // return a function that logs it's
  // arguments when invoked
  return function(){
    console.log(arguments);
  };
}())
// new production.js
// unminified problem for readability
(function(){
  console.log('module1');

  // return a function that logs it's
  // arguments when invoked
  return function(){
    console.log(arguments);
  };
}())(function(){
  console.log('module2');
}());
// => module1
// => module2
// => [undefined]

But wait, there’s no TypeError here…

// it invokes module1
(function(){ console.log('module1'); return function(){ console.log(arguments); };}())
// => module1

//it invokes module2
(function(){ console.log('module2'); }());
// => module2

// equivalent
(function(){ console.log(arguments); })(undefined)
// => [undefined]

There’s no TypeError because of the returned function. The returned function that logs the arguments is then getting invoked with the return value of module2, which is undefined. With that understanding, let’s go back to the original example, where there was a TypeError:

// crockford problem
(function(){console.log('module1');}())(function(){console.log('module2');}());
// => module1
// => module2
// => TypeError: undefined is not a function

// it invokes module1
(function(){ console.log('module1'); }())
// => module1

//it invokes module2
(function(){ console.log('module2'); }());
// => module2

// equivalent
(undefined(undefined))
// => TypeError: undefined is not a function

Conclusion The (function{})(); and (function(){}()); IIFEs can act differently in the missing semicolon situation.

Use linter or a tool to make sure modules aren’t missing trailing semicolons when working on modules.

To be extra safe add a leading semicolon to the IIFE:

// module1.js
;(function() {
  console.log('module1');
})()

// crockford module1.js
;(function(){
  console.log('module1');
}())

// module2.js
;(function() {
  console.log('module2');
})();

// crockford module2.js
;(function() {
  console.log('module2');
}());

// production.min.js
;(function(){ console.log('module1'); })();(function(){ console.log('module2'); })();
// => module1
// => module2

// crockford production.min.js
;(function(){ console.log('module1'); }());(function(){ console.log('module2'); }());
// => module1
// => module2

Hope that helps!

0reactions
xiehongyangcommented, Apr 21, 2016

Cool! help me a lot

Read more comments on GitHub >

github_iconTop Results From Across the Web

Immediately-Invoked Function Expressions and Parentheses
Let's explore the two IIFE methods using parentheses a bit more. Both work the same. It starts to get interesting when one of...
Read more >
Why are parentheses required around JavaScript IIFE?
The version of IIFE that is wrapped in parenthesis works, because this marks the declaration of the internal function declaration as ...
Read more >
Why do you need parentheses for an IIFE if function ... - Reddit
So why is it necessary to wrap it in parentheses to make it an IIFE? What's the parsing rule that causes this?
Read more >
The many ways to write an Immediately Invoked Function ...
An Immediately Invoked Function Expression, or IIFE, is a function that immediately and automatically invokes itself and runs the code inside.
Read more >
IIFE | Dev Cheatsheets - Michael Currin
An IIFE is function that executes immediately after it is defined (usually ... IIFE. Surround the function in brackets before calling it will...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found