JavaScript 模块化编程,已经成为一个迫切的需求。理想情况下,开发者只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块。
但是,JavaScript不是一种模块化编程语言,ES6才就开始支持”类”和”模块“。传统的做法就是利用对象实现模块的效果
1.基本的实现方法
模块是实现特地功能的一组属性和方法的封装
简答的做法就是把模块写成一个对象,所有的模块成员都放到这个对象里面。
var module1 = new Object({
count:0,
m1:function(){
console.log('m1');
},
m2:function(){
console.log('m1');
}
})
上面的函数m1
和m2
,都封装在module1
对象里。使用的时候,就是调用这个对象的属性。
module1.m1();//"m1" 在需要的HTML页面调用
但是,这样的写法会暴露所有模块成员,内部状态可以被外部改写。比如,外部代码可以直接改变内部计数器的值。
module1.count = 10;
封装私有变量:立即执行函数的写法
另一种做法是使用“立即执行函数”(Immediately-Invoked Function Expression,IIFE),将相关的属性和方法封装在一个函数作用域里面,可以达到不暴露私有成员的目的。
var module1 = (function () {
var count = 0;
var m1 = function () {
//...
};
var m2 = function () {
//...
};
return { //这个是属于module1的
m1 : m1,
m2 : m2
};
})();
使用上面的写法,外部代码无法读取内部的count
变量。
console.info(module1.count); //undefined 获取不到模块内部的count
上面的module1
就是 JavaScript 模块的基本写法。
模块放大模式
如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用“放大模式”。
JS模块代码
var module1=(function(){
var count=0;
var m1=function(){
console.log('m1');
};
var m2=function(){
console.log('m2');
}
return {
m1: m1,
m2: m2
}
})();
(function(mod){
mod.m3=function(){
console.log('m3')
}
return mod; //相当于把module1返回
})(module1);
HTML调用
<script src="js/module.js"></script>
<script>
module1.m1();
module1.m2();
console.log(module1)
</script>
module1还有另一个方法m3,但是m3是属于另一个模块的,m3继承module1。有另一个函数,在里面挂载m3的方法,module1传入,mod接收。mod.m3挂载一个方法,把mod返回。
在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上面的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用”宽放大模式”(Loose augmentation)。
var module1 = (function (mod) {
//...
return mod;
})(window.module1 || {});
window.module1
如果有值就把module1
对象赋值给mod
,最终返回,如果没有值那就给一个空对象,在空对象中加载m3
。
命名空间
在一个项目中可能会引入很多个JS文件,JS文件多了,那么JS模块也就增加。模块中声明变量的时候可能会存在冲突问题。那么我们就在自己的模块中造就命名空间,给当前变量对象造就自己的空间。