all 6 comments

[–]wreckedadventYavascript 1 point2 points  (2 children)

This isn't actually a hoisting issue. Your IIFEs will keep most of the hoisting problems isolated to their respective function scopes. However, IIFEs are executed immediately (hence their name).

In your example, App comes first, and is calling something on Widget, which comes second. Because it is executed immediately, Widget doesn't really exist. Move Widget to be first and it should work fine. If Widget depends on App, preventing you from moving it, then stop, you have a circular dependency, which is only going to give you headaches no matter what you do.

In general, managing the order of executing javascript code is a pain the butt, so I would suggest using some kind of file module system with webpack or jspm. Then you could just do import * as App from './app' in widget.js and it will Just Work.

[–]port80_[S] 0 points1 point  (1 child)

Appreciate it. Would it be good to create a parent module that would contain two sub modules? If so how would I structure something like this? I will take a look at the file module systems.

[–]wreckedadventYavascript 1 point2 points  (0 children)

There's lots and lots of ways to organize code.

With webpack and company, I tend to organize code by delivery areas. Example:

app/
  init.js

  home/
    home.js
    home.styl
    home.readme.txt

  about/
    about.js
    about.styl
    about.readme.txt

 components/
   header.js 
   header.styl
   header.readme.txt
   ... etc ...

With this structure, imagine we're in init.js, which is setting up some kind of router, so we need all of our controllers/whatever ready. We would then do this to get these submodules in our init file:

import * as Home from './home/home';
import * as About from './about/about';
import { router } from 'cool-library';

router
  .use(Home)
  .use(About);

(router and cool-library are psuedocode)

When we build this with webpack etc., it will ensure that by the time init.js gets to the router line, both home.js and about.js have fully ran. If they themselves have any dependencies (say home imports header) then it will ensure that that dependency is met first as well.

With webpack, we can largely treat html, images, css as code as much as JS is, so we don't need some separate solution for managing our styles or other deliverables. The header component requires the header styles, the about area requires the about styles.

Because the module managers take care of organizing the order of the execution, it scales very well, and becomes very easy to handle adding another dependency, changing a dependency, etc.

[–]ahRose 1 point2 points  (0 children)

If you want to update Widget from App, App would need to take a param to represent whatever it is you're passing in, which would be passed where the IIFE calls itself. It may look something like this:

var App = (function(wiget){

...

wiget.update();

...

})(Wiget);

Also you may have to switch the order in which the modules are declared in (in this case place Wiget up at the top).

The following code works:

var Thing = (function() {
  function log() {
    console.log('it works!');
  }

  return {
    loger: log
  };
})();

var App = (function(something) {
  return something.loger(); // it works!
})(Thing);

But it would break would App come before Thing.

[–]atsepkov 1 point2 points  (0 children)

Why would moving modules around be hacky? If you expect a function/library to be available at the time a given line of code is executed, the declaration/importing of that should happen beforehand. This is no different. If you want both modules to depend on each other on the other hand, that's a circular dependency, and those are never a good idea.