在Javascript中使用IIFE的范围

时间:2013-01-30 13:56:21

标签: javascript namespaces scope iife

我使用的是使用jsonP共享跨域信息的脚本。 它运作良好,但我需要把它放在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();

有效! (我只是占用了我的全局脚本的一小部分,只是为了向您展示结构,所以如果有任何语法错误,那就不是重点了。)

但是当我把这个代码放在一个自我调用的函数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方法,我真的不明白为什么在添加IIFE之前我无法访问此方法,它不应该&#39 ; t改变任何东西,它只是避免污染全局命名空间。 我认为这只是一个背景问题,但我需要一个解释。

1 个答案:

答案 0 :(得分:4)

使用IIFE的动机是您的变量名称不会“泄漏”到全局范围内。但是,当您使用JSONP时,义务将至少一个变量暴露给全局范围,以便加载的脚本可以调用它(或其中一个方法)。此加载的脚本作为单独的script标记插入到head中,位于完全不同的范围内,因此您只能通过全局范围与其共享变量。

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

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

这是在一个单独的脚本标记中加载的,就像你写的那样:

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

显然,如果这个调用应该有效,myObj需要在全局范围内,所以你应该在IIFE之外移动它的声明,或者在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();
})();

第二个选项可能更有趣,因为它总是会在全局范围内结束,无论您放置片段的位置如何。如果由于某种原因你最终将第一个片段嵌套在另一个IIFE中,你需要记住移动myObj声明,这可能很麻烦。