也许这是我的问题的错误方法,但这就是我在这里的原因。在下面的代码中是带有子模块的JavaScript模块模式的示例。当我构建这个时,我意识到一些子模块需要"调用"彼此的方法。
我知道使用完整的呼叫admin.subModuleB.publicB_2();
是错误的,但这是因为IIFE功能无法调用"他们自己"直到实例化,例如"模块"在主命名空间等中不可用...
我的想法是这种模式对我的情况不正确。模块封装的目的是保持私密性,除非被暴露。那么什么是更好的模式?
var module = (function($, window, document, undefined) {
return {
subModuleA : (function() {
var privateA = 100;
return {
// We have access to privateA
publicA_1 : function() {
console.log(privateA);
// How do I use a method from publicB_1
// the only way is:
module.subModuleB.publicB_2();
// but I don't want to use "module"
},
publicA_2 : function() {
console.log(privateA);
}
}
})(),
subModuleB : (function() {
var privateB = 250;
return {
// We have access to privateB
publicB_1 : function() {
console.log(privateB);
},
publicB_2 : function() {
console.log(privateB);
// I have access to publicB_1
this.publicB_1();
}
}
})()
}
})(jQuery, window, document);
答案 0 :(得分:3)
您实际拥有的是依赖项问题。子模块A依赖于子模块B.有两种解决方案可以想到。
在函数闭包中将两个模块定义为自己的变量,但在一个对象中将它们一起返回。
您真正想要的是可实例化的类,其中A类依赖于B类。
由于解决方案#1最接近您当前的代码,因此我们先探讨一下。
var module = (function($, window, document, undefined) {
var SubModuleA = function() {
var privateA = 100;
return {
// We have access to privateA
publicA_1 : function() {
console.log(privateA);
// Refer to SubModuleB via the private reference inside your "namespace"
SubModuleB.publicB_2();
// but I don't want to use "module"
},
publicA_2 : function() {
console.log(privateA);
}
};
}();
var SubModuleB = function() {
var privateB = 250;
return {
// We have access to privateB
publicB_1 : function() {
console.log(privateB);
},
publicB_2 : function() {
console.log(privateB);
// I have access to publicB_1
this.publicB_1();
}
};
}();
// Return your module with two sub modules
return {
subModuleA : SubModuleA,
subModuleB : SubModuleB
};
})(jQuery, window, document);
这允许您使用局部变量将两个子模块引用到模块的闭包(SubModuleA
和SubModuleB
)。全局上下文仍然可以将它们称为module.subModuleA
和module.subModuleB
。
如果子模块A使用子模块B,则需要解决子模块B是否需要向全局环境显示的问题。
老实说,这个 打破了封装,因为子模块A中并不存在子模块A的所有功能。事实上,如果没有子模块B,子模块A将无法正常运行。
根据您的具体情况,模块模式似乎是一种反模式,也就是说,您正在使用错误的工具来完成工作。实际上,您有两个相互依赖的对象分类。我认为你需要"课程" (JavaScript构造函数)和传统的OOP实践。
首先,让我们重构你的"模块"分为两类:
var module = (function($, window, document, undefined) {
function ClassA(objectB) {
var privateA = 100;
this.publicA_1 = function() {
console.log(privateA);
objectB.publicB_2();
};
this.publicA_2 = function() {
console.log(privateA);
};
}
function ClassB() {
var privateB = 250;
this.publicB_1 = function() {
console.log(privateB);
};
this.publicB_2 = function() {
console.log(privateB);
this.publicB_1();
};
}
// Return your module with two "classes"
return {
ClassA: ClassA,
ClassB: ClassB
};
})(jQuery, window, document);
现在,为了使用这些类,您需要一些代码来从构造函数生成对象:
var objectA = new module.ClassA(new module.ClassB());
objectA.publicA_1();
objectA.publicA_2();
这最大化了代码重用,并且因为您将module.ClassB
的实例传递给module.ClassA
的构造函数,所以您将这些类彼此分离。如果您不希望外部代码管理依赖项,您可以随时调整ClassA
:
function ClassA() {
var privateA = 100,
objectB = new ClassB();
this.publicA_1 = function() {
console.log(privateA);
objectB.publicB_2();
};
this.publicA_2 = function() {
console.log(privateA);
};
}
现在,您可以使用函数闭包中的名称来引用module.ClassB
:ClassB
。这里的优点是外部代码不必为module.ClassA
提供所有依赖项,但缺点是您仍然有ClassA
和ClassB
相互耦合。
同样,这引出了全球背景是否需要向ClassB
透露的问题。