也许这是解决我的问题的错误方法,但这就是我来这里的原因。下面的代码是带有子模块的 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);
最佳答案
您实际上遇到的是依赖关系问题。子模块 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 实践。
使用 JavaScript 构造函数(“类”)
首先,让我们将“模块”重构为两个类:
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
。
关于iife - 具有子模块交叉访问的 JavaScript 模块模式还是更好的模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24084617/