javascript模块模式变量范围

时间:2012-04-25 21:13:54

标签: javascript scope module-pattern

我正在学习javascript和模块模式,但我在我的代码中犯了一个错误,但事实证明我对这个模式的一些概念是错误的。我的基本代码是这样的:

(function(window,$){

//global menu object
var menu = (function(){

    //menu tab component
    var tab = (function(){

        //public properties
        var tab = {
            init:doStuff
        }

        //private properties
        function doStuff(){
            alert("initialising Tab")
        }

        //return public properties
        return tab;
    })();

    //menu curtain component
    var curtain = (function(){

        //public properties
        var curtain = {
            init:doStuff
        }

        //private properties
        function doStuff(){
            alert("initialising Curtain")
        }

        //return public properties
        return curtain;
    })();

    //menu content component
    var content = (function(){

        //public properties
        var content = {
            init:doStuff
        }

        //private properties
        function doStuff(){
            alert("initialising Content")
        }

        //return public properties
        return content;
    })();

    //public properties
    var menu = {
        init:initialiseMenu
    }

    //private properties
    function initialiseMenu(){
        //initialise each component of the menu system
        tab.init();
        curtain.init();
        content.init();

    }

    //final menu object
    return menu;
})();

window.menu = menu;
})(window,jQuery);

然后当我的页面加载并调用代码时:

menu.init();

它按顺序发出警报:

initialising tab
initialising curtain
initialising content

正如我所料。但是,如果我将内容组件更改为:

   //menu content component
    var content = (function(){

        //public properties
        var content = {
            init:doStuff
        }

        //private properties
        function doStuff(){
            alert("initialising Content")
        }

        //CHECK ACCESS TO PREVIOUS VARIABLES
        curtain.init();

        //return public properties
        return content;
    })();

它按顺序发出警报:

initialising curtain
initialising tab
initialising curtain
initialising content

所以我看到它能够访问窗帘变量,即使它没有作为参数传递给模块。 我认为每个模块都是自包含的,但我发现事实并非如此,是否有一个模块只能访问你想要的变量呢?特别是我的例子会有所帮助, 谢谢Dan。

3 个答案:

答案 0 :(得分:2)

每个模块都不是自包含的,而是创建一个新范围,它是创建它的超集。在Javascript中唯一定义新范围的是function语句。在新范围内,除非被同名变量覆盖,否则外部范围内的所有内容都是可见的。内部范围内的任何东西都不会被外部的东西看到。

var global;
function outer() {
    var outerVar;

    function inner() {
        var innerVar;

        // global, outerVar, and innerVar are visible

    }   
    function inner2() {
        var inner2var, outerVar;

        // global and inner2var are visible
        // outerVar hides the previous outerVar, which is no longer accessible

    }

    // global and outerVar (the first one) are visible

} 

您的功能是自动执行的事实没有任何区别。在外部作用域中创建的任何内容都将在您的内部作用域中可见,除非您创建一个同名的新的局部变量来取代它。

就你的内在范围而言,在它之外创建的任何东西都与全局范围大致相同。 (而全局只是在默认范围内创建的变量,在浏览器中为“窗口”)。

你可以想到一个像单向玻璃背后的内在范围。你仍然可以看到世界上的一切,但世界却看不到你。而且你总是可以选择阻挡单向玻璃,这样你就再也看不到了。但是没有什么能够看到的。

答案 1 :(得分:0)

任何函数的当前范围都可以看到它包含的范围。因此,内容仍然可以访问菜单中的任何变量,包括幕布。

答案 2 :(得分:0)

这种情况正在发生,因为当您在每个对象中调用“return”时,您将为组件变量分配返回值,该值是每个组件中的内部“公共属性”对象。

var tab = (function(){

    //public properties
    var tab = {
        init:doStuff
    }

    //private properties
    function doStuff(){
        alert("initialising Tab")
    }

    //return public properties
    return tab;
})();

在这里,您将使用正在执行的匿名函数的结果分配原始变量“tab”。这种情况下的对象是:

    var tab = {
        init:doStuff
    }

因为在函数执行结束时返回此对象。

要实现您所追求的目标,请尝试返回一个具有“公共”修饰符函数的对象,该函数可以访问函数范围内的变量。在函数内创建的任何变量仅具有该范围内的函数或函数的范围,从而使它们实际上是私有的(Javascript在功能上是作用域的)。以下示例可以帮助您使用代码:

var tab = (function(){

    //public properties
    var PublicProperties = {
        init:doStuff,
        modifyPrivateVar: function(value){
            this.somePrivateVariable = value;
        }
    }

    //private variables/properties
    var doStuff = function(){
        alert("initialising Tab")
    }

    var somePrivateVariable = 'private!';

    //return public properties
    return PublicProperties;
})();

现在,您的变量'tab'将通过执行匿名函数分配返回给它的值(PublicProperties对象)。您可以访问“init”和“modifyPrivateVar”函数,但不能直接调用“doStuff”或更改“somePrivateVariable”。这表明您可以通过修饰符函数更改变量,但无法直接访问它,从而使其实际上是私有的。

如果希望将“init”函数作为构造函数调用,则必须在执行组件的匿名函数执行时执行“构造函数”,或者只是在线编写代码,它将作为组件的匿名函数执行....否则你不应该返回任何与init函数相关的东西,如果它是私有的,只返回可以用来以安全的方式修改/激活你的对象的函数。