2012-04-25 55 views
0

我学习JavaScript和模块模式,但我在我的代码犯了一个错误,它不对证明一些我虽然是真实的关于这个模式的概念。我的基本代码是这样的:的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 

因此,我认为,这是能够访问,即使它WASN帷幕变量作为参数传入模块。 我认为,每个模块将自包含的,但我发现,这是不是这样的,反正有做一个模块只能访问变量,你想它呢?特别是对我的例子会有所帮助, 谢谢丹。

回答

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 

} 

事实上,你的函数是自执行没有什么区别。在外部范围中创建的任何内容都将在您的内部范围内可见,除非您创建一个具有相同名称的新的本地变量,而不用替代它。

至于你内心的范围而言,这是外面创建任何东西是一样一样的一个全球性的。 (而全局只是一个在默认范围内创建的变量,“浏览器中的窗口”)。

你能想到的范围内的就像是单向的玻璃后面。你仍然可以看到世界上的一切,但世界看不到你。你总是可以选择阻止单向玻璃,这样你就不会再看到了。但是什么也看不到。

+0

这是ES6的发布吗? – 2016-06-17 13:50:10

+0

是的,ES6是ES5的超集。有一些新的作用域结构像'let',但是这个代码仍然有效 – 2016-06-17 14:31:17

0

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

0

这是发生,因为当你调用中的每个对象“回归”,你要分配到组件变量的返回值,这是内在的“公共属性”的对象中每个组件。

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 
    } 

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

为了达到目标,请尝试返回一个具有访问函数范围内变量的'public'修饰符函数的对象。任何在函数中创建的变量都只适用于其范围内的那个函数或函数,从而使它们实际上是私有的(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; 
})(); 

现在你的变量“选项卡”将被赋予值由匿名函数的执行返回到它(PublicProperties对象)。您将可以访问函数“init”和“modifyPrivateVar”,但不能直接调用“doStuff”或更改“somePrivateVariable”。这表明您可以通过修饰符函数更改变量,但无法直接访问它,从而使其变得非常私密。

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