简体   繁体   English

javascript模块模式变量范围

[英]javascript module pattern variable scope

I am learning javascript and the module pattern, but I made a mistake in my code and it proved wrong some of the concepts I though were true about this pattern. 我正在学习javascript和模块模式,但是我在我的代码中犯了一个错误,但事实证明我对这个模式的一些概念是错误的。 My basic code is like this: 我的基本代码是这样的:

(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);

Then When my page loads and the code is called: 然后当我的页面加载并调用代码时:

menu.init();

It gives the alerts in order: 它按顺序提供警报:

initialising tab
initialising curtain
initialising content

As I expect. 正如我所料。 But if I change the content component to be like this: 但是,如果我将内容组件更改为:

   //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;
    })();

it gives out the alerts in order: 它按顺序发出警报:

initialising curtain
initialising tab
initialising curtain
initialising content

So I see that it is able to access the curtain variable even though it wasn't passed into the module as an argument. 所以我看到它能够访问窗帘变量,即使它没有作为参数传递给模块。 I thought that each module would be self contained but I have discovered that this is not the case, Is there anyway to make a module only have access to variables you want it too? 我认为每个模块都是自包含的,但我发现事实并非如此,是否有一个模块只能访问你想要的变量呢? in particular to my example would be helpful, Thanks Dan. 特别是我的例子会有所帮助,谢谢Dan。

Each module is not self contained, rather, it creates a new scope that is a superset of the one in which it was created. 每个模块都不是自包含的,而是创建一个新范围,它是创建它的超集。 The only thing that defines a new scope in Javascript is the function statement. 在Javascript中唯一定义新范围的是function语句。 Within a new scope, everything from the outer scope is visible unless overridden by a variable of the same name. 在新范围内,除非被同名变量覆盖,否则外部范围内的所有内容都是可见的。 Nothing in the inner scope is visible to something outside it. 内部范围内的任何东西都不会被外部的东西看到。

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

} 

The fact that your functions are self-executing doesn't make a difference. 您的功能是自动执行的事实并没有什么不同。 Anything created in an outer scope will be visible in your inner scope, unless your create a new local variable of the same name which supercedes it. 在外部作用域中创建的任何内容都将在内部作用域中可见,除非您创建一个同名的新局部变量来取代它。

As far as your inner scope is concerned, anything that was created outside it is much the same as a global. 就你的内在范围而言,在它之外创建的任何东西都与全局范围大致相同。 (And a global is just a variable created in the default scope, "window" in a browser). (而全局只是在默认范围中创建的变量,在浏览器中为“窗口”)。

You could think of an inner scope like being behind one-way glass. 你可以想到一个像单向玻璃背后的内在范围。 You can still see everything in the world, but the world can't see you. 你仍然可以看到世界上的一切,但世界却看不到你。 And you can always choose to block the one-way glass so you can no longer see out. 而且你总是可以选择阻挡单向玻璃,这样你就再也看不到了。 But nothing will ever be able to see in. 但是没有什么能够看到的。

The current scope for any function can see it's contained scope. 任何函数的当前范围都可以看到它包含的范围。 So, content still has access to any variables in menu, which include curtain. 因此,内容仍然可以访问菜单中的任何变量,包括窗帘。

This is happening because when you call 'return' in each object, you are assigning to the component variable the return value, which is the inner 'public properties' object in each of your components. 发生这种情况是因为当您在每个对象中调用“return”时,您将向组件变量分配返回值,该值是每个组件中的内部“公共属性”对象。

var tab = (function(){

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

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

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

Here you are assigning the original variable 'tab' with the result of the anonymous function you are executing. 在这里,您将使用正在执行的匿名函数的结果分配原始变量“tab”。 The object in this case is: 这种情况下的对象是:

    var tab = {
        init:doStuff
    }

because you return this object at the end of the function's execution. 因为在函数执行结束时返回此对象。

To achieve what you're after, try returning an object that has 'public' modifier functions that access variables within the function's scope. 要实现您所追求的目标,请尝试返回一个具有“公共”修饰符函数的对象,该函数可以访问函数范围内的变量。 Any variable created within a function has scope only to that function or functions within its scope, thereby making them effectively private (Javascript is functionally scoped). 在函数内创建的任何变量仅具有该范围内的函数或函数的范围,从而使它们实际上是私有的(Javascript在功能上是作用域的)。 The following example should help you with your code: 以下示例可以帮助您完成代码:

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;
})();

Now your variable 'tab' will be assigned the value returned to it (the PublicProperties object) by the execution of the anonymous function. 现在,通过执行匿名函数,将为变量“tab”分配返回给它的值(PublicProperties对象)。 You will have access to the functions "init" and "modifyPrivateVar", but you cannot call "doStuff" or change "somePrivateVariable" directly. 您可以访问“init”和“modifyPrivateVar”函数,但不能直接调用“doStuff”或更改“somePrivateVariable”。 This demonstrates that you can change a variable through a modifier function but cannot access it directly, thereby making it effectively private. 这表明您可以通过修饰符函数更改变量,但不能直接访问它,从而使其实际上是私有的。

If you wish your "init" function to be called as a constructor, you must execute your "constructor function" within the execution of the component's anonymous function execution, or just write the code in-line and it will be executed as the component's anonymous function executes.... otherwise you should not be returning anything related to the init function if it is private, only return functions that can be used to modify/activate your objects in a safe way. 如果希望将“init”函数作为构造函数调用,则必须在执行组件的匿名函数执行时执行“构造函数”,或者只是在线编写代码,它将作为组件的匿名执行函数执行....否则你不应该返回任何与init函数相关的东西,如果它是私有的,只返回可以用来以安全的方式修改/激活你的对象的函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM