Javascript中IIFE的作用域

Javascript中IIFE的作用域,javascript,namespaces,scope,iife,Javascript,Namespaces,Scope,Iife,我正在使用一个使用jsonP共享跨域信息的脚本。 它工作得很好,但我需要把它放在生活中 var domain = "http://example.com/"; var myObj = { recupData : function(data){ if (data.id) { console.log(data.id); } }, scriptTag : function() { var siteOrigi

我正在使用一个使用jsonP共享跨域信息的脚本。 它工作得很好,但我需要把它放在生活中

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();
真管用!(我只是从全局脚本中提取了一小部分,只是为了向您展示其结构,因此,如果存在任何语法错误,这不是重点)

但是当我把这段代码放在一个IIFE中,一个自调用函数中,我会遇到一些麻烦

(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();
})();
我得到一个错误myObj没有定义,这个错误来自scriptTag方法,我真的不明白为什么我不能访问这个方法,直到我添加了一个iLife,它不应该改变任何东西,它只是避免污染全局名称空间。
我认为这只是一个上下文问题,但我需要一个解释。

使用IIFEs的动机是变量名不会“泄漏”到全局范围。但是,当您使用JSONP时,您有义务向全局范围公开至少一个变量,以便加载的脚本可以调用它(或其方法之一)。这个加载的脚本作为一个单独的
脚本
标记插入到
中,在一个完全不同的范围内,因此您只能通过全局范围与它共享变量

例如,假设您对
http://mydomain.com/check?q=myObj.recupData
产生如下响应:

myObj.recupData({"id":123,"more":"stuff"})
这将加载到一个单独的脚本标记中,就像您编写了:

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

第二个选项可能更有趣,因为无论您将代码段放在何处,它始终会在全局范围内结束。如果出于某种原因,您最终将第一个代码段嵌套在另一个IIFE中,那么您需要记住移动
myObj
声明,这可能会很麻烦。

@apsillers是的,这是一个好字符串,当您告诉我的回调不使用myObj时,您的意思是什么?错误是在追加脚本之后还是之前出现的?您添加的脚本代码是否引用了
myObj
?@JAAulde是的,脚本标记是在我得到错误之前创建的。我只是创建一个http请求来从另一个服务器域获取数据。哦,非常感谢,我真的没有注意到这个事实。所以你不认为有任何方法可以避免我的对象必须是全局的吗?例如,如果使用jQuery jsonP,则可以将其包含在IIFE中。@M4nch4k您的回调不必是“全局的”,因为它可以在另一个对象中命名,但必须从全局范围访问。甚至jQuery也向全局范围添加了一个回调,名为
jquery1436746853
(我认为它使用了时间戳?),但您根本看不到它,因为jQuery抽象了您使用它的需要。@M4nch4k jQuery用于JSONP请求,它的行为类似于委托,并将结果存储在变量中。然后,它使用回调函数检索这些结果,以便回调函数获得正确的数据。由于回调是作为函数(而不是名称)传递的,因此它不需要是全局的,并且保持其作用域。因此,如果我的整个脚本包含在IIFE中,我需要将我的函数ou放在我的对象中,并像window.scriptTag=函数(数据){}那样调用它,为了避免我的主对象是全局对象。@M4nch4k如果你不想公开
myObj
,你需要在全局作用域中创建一个委托函数,但要在本地访问
myObj
,这样你仍然可以使用它。例如:<代码> WiDOW.MyjSnPultAudie=函数(数据){MyObj.doSuffOffice(数据);}如果您需要很多这样的委托来支持大量的JSONP请求,您可以考虑将它们放到单独的命名空间中以减少全局混乱。在任何情况下,您都需要在全局范围中至少放置一些内容,以便加载的脚本能够访问。
// 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();
})();