我想知道是否可以在不同的模块中共享变量。
例如,在我的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
模块中的变量。
答案 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;