Scope with IIFE in Javascript

I am using a script that use jsonP to exchange cross domain information. It works well, but I need to put it inside the IIFE.

var domain = "http://example.com/";
var myObj = {
    recupData : function(data){
        if (data.id) {
            console.log(data.id);
        }
    },
    scriptTag : function() {
        var siteOrigin = domain+"check?q=myObj.recupData",
            script = document.createElement('script');
        script.type = 'text/javascript';
        script.async = true;
        script.src = siteOrigin;
        document.getElementsByTagName('HEAD')[0].appendChild(script);
    }
}
myObj.scriptTag();

      

It works! (I just took a very small part of my global script to show you the structure, so if there's a syntax error in there, that's not the point).

But when I put this code in IIFE, self invoked function, I am having problems.

(function(){
var domain = "http://example.com/";
var myObj = {
    recupData : function(data){
        if (data.id) {
            console.log(data.id);
        }
    },
    scriptTag : function() {
        var siteOrigin = domain+"check?q=myObj.recupData",
            script = document.createElement('script');
        script.type = 'text/javascript';
        script.async = true;
        script.src = siteOrigin;
        document.getElementsByTagName('HEAD')[0].appendChild(script);
    }
}
myObj.scriptTag();
})();

      

I am getting the error myObj is not defined, the error is coming from the scriptTag method and I really don't understand why I can't access this method until I add the IIFE, it shouldn't change anything, It just avoids polluting the global namespace. I think this is just a context issue, but I need an explanation.

+3


source to share


1 answer


The motivation for using the IIFE is that your variable names don't "leak" into the global scope. However, when using JSONP, you are required to expose at least one variable to the global scope, so the loaded script can call it (or one of its methods). The uploaded script is inserted as a separate tag script

in head

a completely different scope and therefore you can only share the global scopes with it.

For example, imagine that your call http://mydomain.com/check?q=myObj.recupData

invokes a response like:

myObj.recupData({"id":123,"more":"stuff"})

      

This is loaded inside a separate script tag, as if you had written:



<script type="text/javascript">
myObj.recupData({"id":123,"more":"stuff"})
</script>

      

Obviously, if this call is to work, myObj

must be in the global scope, so you must move its declaration outside of the IIFE, or explicitly register it with the object window

:

// Global declaration
var myObj;
(function(){
    var domain = "http://mydomain.com/";
    myObj = { ... };
    myObj.scriptTag();
})();

// Registering on window
(function(){
    var domain = "http://mydomain.com/";
    // Also get it as a local variable
    // for a minor scope lookup optimization
    var myObj = window.myObj = { ... };
    myObj.scriptTag();
})();

      

The second option might be more interesting as it will always be globally no matter where you place the snippet. If for some reason you insert the first fragment inside another IIFE, you will need to remember the sentence as well myObj

, which can be cumbersome.

+4


source







All Articles