我真的不喜欢我的所有javascript代码只在一个文件中结束,我尝试使用像require.js这样的库来帮助我模块化,但它们最终让我有点复杂。所以我想知道我是否可以做这样的事情。
背景: 假设我想要一个不同的模块来处理随机数生成。我创建了一个新文件(首字母是我自制的约会)
// File : RandomNumberGenerator.js
(function(){
// export this to the outer world
_randomGenerator = new RandomNumberGenerator();
function RandomNumberGenerator() {
}
RandomNumberGenerator.prototype.getRandomNumber = function(rangeLower, rangeHigher) {
if(rangeLower !== undefined && rangeHigher === undefined) { // user passed in just one parameter
rangeHigher = rangeLower;
rangeLower = 0;
}else if (rangeLower === undefined && rangeHigher === undefined) {
return (Math.random());
}
return (Math.floor((Math.random() * (rangeHigher - rangeLower)) + rangeLower));
};
})();
现在_randomGenerator
对全局范围可见。我添加了' _'再次成为一个自制的会议。
现在我可以在我的主要js文件中使用它,如
(function() {
console.log(_randomGenerator.getRandomNumber(5));
})();
我可以这样做吗?从长远来看,我有什么东西可以解决问题吗?通过做这样的事情是否有可能污染全球范围?
答案 0 :(得分:2)
您所描述的是Immediately invoked function expression模块模式。
要导出需要将它们附加到全局window
对象的函数和对象,通常建议您将它们放在命名空间下以避免与其他代码冲突:
(function() {
function RandomNumberGenerator() {
}
RandomNumberGenerator.prototype.getRandomNumber = function(rangeLower, rangeHigher) {
...
};
// Create new namespace
window.MyModule = {};
// Export the RandomNumberGenerator
window.MyModule.RandomNumberGenerator = RandomNumberGenerator;
// Export a single instance
window.MyModule.defaultRandomNumberGenerator = new RandomNumberGenerator();
})();
您还可以将值导入IIFE,从而可以创建别名:
(function(rng, max) {
console.log(rng.getRandomNumber(max));
})(MyModule.defaultRandomNumberGenerator, 5);
我可以这样做吗?
是
从长远来看,我有什么东西可以忽视吗?
不要让你的IIFE变得太大,否则你将失去利益。小型明确定义的模块更易于维护。
此外,如果你想要两个模块共享同一个命名空间,你需要做一些比上面的例子更精细的事情,否则一个模块会覆盖另一个模块。
IIFE可以保持状态,但它们实际上是单身,试图确保你创建对象并将任何状态置于那些状态以避免global state。
是否有可能通过这样做来污染全球范围?
是的,这是可能的;您仍然应该仔细命名您的命名空间 - 例如,不要使用window.jQuery
!
答案 1 :(得分:1)
是的,你可以这样做。事实上,这是一种非常频繁的模式。它通常与JS文件的自动连接相结合,保持源文件(非连接)和生产文件之间的区别(连接,并且通常也缩小)。
只是明确表示您正在创建窗口对象的属性。变化
_randomGenerator = new RandomNumberGenerator();
到
window._randomGenerator = new RandomNumberGenerator();
strict mode中必须使用此明确声明。
答案 2 :(得分:0)
虽然您可以模块化这样的代码,但您仍然可能会引入大量的全局变量。你正在使用一种防御策略,通过添加_前缀,但是根本不使用它们更安全。
您实际上只需要一个模块模式。只要你的第一个文件有这样的东西:
window.module = {};
然后其余模块可以将自己注册为模块对象的属性,而不必扭曲它们的名称。
module.randomNumberGenerator = new RandomNumberGenerator();
function RandomNumberGenerator() {
...
}
然后在任何其他文件中,您可以使用该实例。
var rng = module.randomNumberGenerator;
// ...
var number = rng.getRandomNumber();
答案 3 :(得分:0)
这样可行,但它过于复杂,除非您声明了一些数据需要放入范围以保持隔离。
对于您的示例,您可以直接创建对象,而不是只使用构造函数来创建单个实例:
// File : RandomNumberGenerator.js
_randomGenerator = {
getRandomNumber: function(rangeLower, rangeHigher) {
if(rangeLower !== undefined && rangeHigher === undefined) { // user passed in just one parameter
rangeHigher = rangeLower;
rangeLower = 0;
}else if (rangeLower === undefined && rangeHigher === undefined) {
return (Math.random());
}
return (Math.floor((Math.random() * (rangeHigher - rangeLower)) + rangeLower));
}
}
如果你有一个类,如果你没有任何静态数据,你仍然不需要将它包装在一个范围内:
function SomeClass() {
// ...
}
SomeClass.prototype.someMethod = function(){
// ...
}
如果您有类的静态数据,则可以使用范围,例如跟踪所有实例:
var SomeClass = (function(){
var instances = [];
function SomeClass() {
instances.push(this);
}
SomeClass.prototype.getAllInstances = function(){
return instances;
}
// expose the constructor
return SomeClass;
})();