js基础 ---- 如何实现模块化
一、模块化编程形成的原因
随着网页的发展 页面逻辑也越来越复杂 所带来的诸如逻辑混乱,页面复杂,可维护性差,全局变量暴露等问题接踵而至
开发者需求去管理网页的逻辑
Javascript模块化编程:发者只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块
现在模块化的编程思想已经越来越普遍
二、模块化编程的优点
(1)、解决项目中的全局变量污染的问题
(2)、开发效率高,有利于多人协同开发
(3)、职责单一,方便代码复用和维护
(4)、解决文件依赖问题,无需关注引用文件的顺序
三、模块化的几种规范
(1)、AMD规范
含义:它是一个在浏览器端模块化开发的规范,服务器端的规范是CommonJS 模块将被异步加载,模块加载不影响后面语句的运行。所有依赖某些模块的语句均放置在回调函数中
define() 函数
AMD规范只定义了一个函数 define
,它是全局变量。函数的描述为:
define(id?, dependencies?, factory)
id:指定义中模块的名字,可选
如果没有提供该参数,模块的名字应该默认为模块加载器请求的指定脚本的名字。如果提供了该参数,模块名必须是“顶级”的和绝对的(不允许相对名字)
依赖dependencies:是一个当前模块依赖的,已被模块定义的模块标识的数组字面量
依赖参数是可选的,如果忽略此参数,它应该默认为["require", "exports", "module"]。然而,如果工厂方法的长度属性小于3,加载器会选择以函数的长度属性指定的参数个数调用工厂方法
工厂方法factory,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值
实例:
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
exports.verb = function() {
return beta.verb();
//Or:
return require("beta").verb();
}
});
)
(2)、CommonJS 规范
CommonJS
是服务器端模块的规范,Node.js
采用了这个规范。Node.JS首先采用了js模块化的概念
根据CommonJS
规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global
对象的属性
输出模块变量的最好方法是使用module.exports
对象
var i = 1;
var max = 30;
module.exports = function () {
for (i -= 1; i++ < max; ) {
console.log(i);
}
max *= 1.1;
};
四、模块化的原生实现实现
(1)、原始写法
模块就是实现特定功能的一组方法
只要把不同的函数(以及记录状态的变量)简单地放在一起,就算是一个模块。
function fn1(){...}
function fn2(){...}
fn1 和 fn2 就组成了一个模块 使用的时候直接调用即可
缺点:"污染"了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系
(2)、对象写法
对第一种方法的一种优化写法 可以把模块写成一个对象,所有的模块成员都放到这个对象里面
var module1 = new Object{
_count: 0,
fn1: function(){...}
fn2: function(){...}
}
调用:module1.fn1()
但是,这样的写法会暴露所有模块成员,内部状态可以被外部改写。比如,外部代码可以直接改变内部计数器的值
module1._count = 5
(3)、立即执行函数写法
使用 立即执行函数 可以优化对象写法 暴露所有模块成员的问题
var module1 = (function(){
var _count = 0;
var m1 = function(){
//...
};
var m2 = function(){
//...
};
return {
m1 : m1,
m2 : m2
};
})();
但是外部也无法读取内部的 _count 变量
console.info(module1._count); //undefined
(4)、放大模式
如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用"放大模式"(augmentation)
var module1 = (function (mod){
mod.m3 = function () {
//...
};
return mod;
})(module1);
上面的代码为module1模块添加了一个新方法m3(),然后返回新的module1模块
(5)、宽放大模式
在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上一节的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用"宽放大式"。
var module1 = ( function (mod){
//...
return mod;
})(window.module1 || {});
与"放大模式"相比,"宽放大模式"就是"立即执行函数"的参数可以是空对象