我正在学习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
所以我看到它能够访问窗帘变量,即使它没有作为参数传递给模块。 我认为每个模块都是自包含的,但我发现事实并非如此,是否有一个模块只能访问你想要的变量呢?特别是我的例子会有所帮助, 谢谢Dan。
答案 0 :(得分: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
}
您的功能是自动执行的事实没有任何区别。在外部作用域中创建的任何内容都将在您的内部作用域中可见,除非您创建一个同名的新的局部变量来取代它。
就你的内在范围而言,在它之外创建的任何东西都与全局范围大致相同。 (而全局只是在默认范围内创建的变量,在浏览器中为“窗口”)。
你可以想到一个像单向玻璃背后的内在范围。你仍然可以看到世界上的一切,但世界却看不到你。而且你总是可以选择阻挡单向玻璃,这样你就再也看不到了。但是没有什么能够看到的。
答案 1 :(得分:0)
任何函数的当前范围都可以看到它包含的范围。因此,内容仍然可以访问菜单中的任何变量,包括幕布。
答案 2 :(得分:0)
这种情况正在发生,因为当您在每个对象中调用“return”时,您将为组件变量分配返回值,该值是每个组件中的内部“公共属性”对象。
var tab = (function(){
//public properties
var tab = {
init:doStuff
}
//private properties
function doStuff(){
alert("initialising Tab")
}
//return public properties
return tab;
})();
在这里,您将使用正在执行的匿名函数的结果分配原始变量“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函数相关的东西,如果它是私有的,只返回可以用来以安全的方式修改/激活你的对象的函数。