1

我正在学习 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

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

4

3 回答 3

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

} 

您的函数是自动执行的这一事实并没有什么不同。在外部范围内创建的任何内容都将在您的内部范围内可见,除非您创建一个新的同名局部变量来取代它。

就您的内部范围而言,在其外部创建的任何内容都与全局相同。(全局只是在默认范围内创建的变量,即浏览器中的“窗口”)。

您可以将内部范围想象为单向玻璃后面。你仍然可以看到世界上的一切,但世界看不到你。而且您始终可以选择挡住单向玻璃,这样您就再也看不到外面了。但是什么都看不到。

于 2012-04-25T21:23:18.107 回答
0

任何函数的当前作用域都可以看到它的包含作用域。因此,内容仍然可以访问菜单中的任何变量,包括窗帘。

于 2012-04-25T21:25:40.190 回答
0

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

var tab = (function(){

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

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

    //return public properties
    return 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 函数相关的任何内容,只返回可用于以安全方式修改/激活对象的函数。

于 2012-04-25T21:45:03.267 回答