Code Monkey home page Code Monkey logo

Comments (8)

hshoff avatar hshoff commented on May 5, 2024 12

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!

from javascript.

reissbaker avatar reissbaker commented on May 5, 2024

For modules we've decided on this:

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

...But I have no particular preference on where parens should go for IIFEs that aren't also modules. Usually they're not very useful -- if it needs to be hidden, make it its own module -- but in the cases where they are it doesn't really matter to me. Both seem equally readable.

Is there enough of a difference to make this worth codifying?

from javascript.

jcutrell avatar jcutrell commented on May 5, 2024

A fantastically thorough explanation.

from javascript.

egonyuri avatar egonyuri commented on May 5, 2024

Incredible explanation.

from javascript.

mikejoyceio avatar mikejoyceio commented on May 5, 2024

Great explanation. Thanks.

from javascript.

jaan avatar jaan commented on May 5, 2024

Good Explanation @hshoff

from javascript.

freeethy avatar freeethy commented on May 5, 2024

Great explanation @hshoff . Thanks.

from javascript.

xiehongyang avatar xiehongyang commented on May 5, 2024

Cool! help me a lot

from javascript.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.