如何在不同的javascript模块中共享变量

时间:2012-09-14 11:24:06

标签: javascript scope

我想知道是否可以在不同的模块中共享变量。

例如,在我的common模块中,我定义了一些全局变量和util方法

(function(){
  var name="";
})();

在其他模块中,我想访问name变量,例如,在app模块中:

var kk=name; // access the name
//other thing

但是我不想将name导出到全局上下文。

有可能吗?

更新


为什么我问这个问题是我发现谷歌这样做:

在Google地图example page中:

加载以下js: main.js

其内容是:

  

((function(){// xxxxxx})。call(this);

然后它加载map个compnets,如下所示:

  

google.maps。 _ gjsload _ ('map','\'使用strict \';函数Ut(){}函数   VT(A,B,C).......');

虽然map模块可以使用main模块中的变量。

2 个答案:

答案 0 :(得分:1)

修改

这非常简单:如果您在示例页面上打开控制台,并查看main.js的来源(单击左下角的按钮,看起来像[{}]),您会注意到整个脚本是一个很大的功能,使用.call(this)调用。后者是必要的,因为严格模式(屏蔽全局对象,除非它明确地设置为调用者上下文) 此函数声明此函数范围内的所有函数,对象和方法,形成闭包。因此,在此范围内声明的所有函数也可以访问所有变量。最后,google属性被指定为全局对象的属性,从而暴露了闭包。

(function()
{
    'use strict';
    console.log(this);//would be undefined
}).call(this);//but the global object is explicitly set as context, so this === window

(function()
{
    'use strict';
    var closureScope = 'Global object can\'t see me';
    var google = {visible:'Yes, I was assigned as a property to the global object'};
    google.closureScope = closureScope;//expose initial value of closureScopeVariable
    google.showBenefits = function()
    {//context here is google object, this points to google
        this.closureScope = 'I looked like the closure variable';//reassign
        console.log(this.closureScope === closureScope);//logs false
    };
    google.restoreOriginal = function()
    {
        this.closureScope = closureScope;//reassign closureScope's original value
    };
    //expose:
    this.google = google;
}).call(this);
//global object:
google.closureScope = 'Foobar';
google.restoreOriginal();
console.log(google.closureScope);//Global object can't see me

据我所知,这可能看起来并不那么清楚,但实际上,会发生什么:每个函数都有自己的范围。当该函数返回时,该范围中声明的所有变量都被垃圾收集(GC),除非有一个引用它们的对象。
在这种情况下,google是一个在匿名函数范围内声明的对象。然后将此Google对象的引用分配给全局对象,它恰好与对象变量具有相同的名称,但它也可以像这样公开:

window.foobar = google;
window.foobar.closureScope;//works
window.google;//undefined

Google是全局对象的属性,引用在函数范围内创建的对象。它引用的对象使函数的作用域(以及在该作用域中声明的所有变量)保持活动状态。这就是为什么看起来你几乎可以直接访问闭包变量,但同样,它是 REFERENCE 。如果你熟悉C(++)编程,那么这就是伪代码中发生的事情:

GoogleObj google = new Google();
GoogleObj &window.google = google;
//or in pseudo-C:
GoogleObj *google;
GoogleObj **window.google = &google;//pointer to pointer ~= reference

基本上全局google只包含实际google对象的内存地址,它指向它,它引用它,它只是告诉JS在哪里查找内存中的值,... < br />实际对象无法直接访问,它位于内存中的某个位置,以及与其一起声明的所有局部变量,它们都有地址,但全局对象不知道这些。它只是转到它知道的一个地址,询问它需要什么,原始谷歌对象符合。

我很难以连贯,全面的方式解释所有这些,但是perhaps this article可能会对这个问题有所了解。当我开始研究闭包时,我发现图表非常有用。


你不能,不是这样。闭包的关键在于您可以设置只能在该特定范围内引用的变量。但可以做的是使用特权方法,或者(不是好的做法,但可能)完全将变量分配给全局对象。

(function()
{
    var name = 'foo';
    //do stuff
    window.name = name;//expose to global object
})();//THIS IS BLUNT AND DANGEROUS

var safer = (function()
{
    var name = 'foo';
    return {name:name};
});
console.log(safer.name);//logs foo

如果你真的,真的需要全局:

var safer = (function()
{
    var closureVars = {name:'foo'};
    var name = 'foo';
    return function(privateName,globalName)
    {
        globalName = globalName || privateName;
        window[globalName] = closureVars[privateName];
    };
});
safer('name');//sets window.name to 'foo'

但最重要的是,特别是在您的情况下(访问某些“私有”变量),特权获取者似乎是最好的方式:

var module = (function()
{
    var closureVars = {name:'foo';}
    return {get:function(name)
        {
            return closureVars[name];
        },
        set:function(name,val)
        {
            closureVars[name] = val;
        }
    };
};
var name = module.get('name');//sets a global name variable to 'foo'
module.set('name2',module.get('name'));//and so on

应该这样做

答案 1 :(得分:0)

在对Quentin和Elias进行正确批评后更新

您可以像这样定义模块:

var module = (function(){
    // your module definition
    var module = {};

    // set name as a property of the module
    module.name="";

    // return the module object
    return module;
})();

现在使用

访问模块外部的名称
var kk = module.name;