模块化编程
随着应用越来越复杂,js必然走向模块化编程。如何模块化编程呢?
#####一、原始写法
模块是实现特定功能的一组方法。
function m1(){
//...
}
function m2(){
//...
}
例如以上的m1()和m2() 缺点:污染全局变量,可能与其他模块发生命名冲突。模块成员之间看不出直接关系。
#####二、对象写法
我们想到可以把模块写成一个对象,所有模块成员都放在对象里。
var module1 = new Object({
_count : 0,
m1 : function (){
//...
},
m2 : function (){
//...
}
});
调用写法:module1.m1()
缺点:写法会暴露所有的模块成员,内部状态可以被外部改写。比如 module1._count = 4;
#####三、立即执行函数写法
var module1 = (function(){
var _count = 0;
var m1 = function(){
//...
};
var m2 = function(){
//...
};
return {
m1 : m1,
m2 : m2
};
})();
利用立即执行函数只暴露想要使用的模块成员,保护剩余成员。
四、放大模式
当模块很大,不得不拆分,模块成员之间有继承关系的时候,就需要放大模式。
var module1 = (function (mod){
mod.m3 = function () {
//...
};
return mod;
})(module1);
放大模式可以通过给传入的module进行扩展,从而实现“继承”
#####五、模块规范 (CommonJs)
因为有了模块,所以我们需要对模块写法有一个规范。目前通用的规范有CommonJS、AMD、CMD nodeJs被创造出来以后,将javascript用于服务器端编程,这时候必须要有模块化的写法。 nodeJS的模块系统,参照CommonJs规范实现。
var math = require('math');
math.add(2,3); // 5
全局性的方法require(),用于加载模块。 但是有一个问题,当这种写法在浏览器端运行时,会导致第一行代码运行以后,应用会停住,等math.js加载完成以后才会继续执行。 对于服务器来说,所有资源都在本地,加载不成问题,但是对于浏览器,这是大问题。
六、AMD
由于以上,产生了异步加载规范AMD。实现是requireJS。
require([module], callback); AMD调用require方法,但是需要传入加载模块和回调函数。
require(['math'], function (math) {
math.add(2, 3);
});
math模块写法
define(function (){
var add = function (x,y){
return x+y;
};
return {
add: add
};
});
Require.js理论上只能加载用define()函数定义的模块,但是实际上也可以加载非标准的模块。
调用之前使用require.config()方法,定义它们的一些特征,就可以调用了。
七、CMD
CMD是在AMD基础上又做了优化的一种模块化。实现是SeaJS。
// 定义模块 myModule.js
define(function(require, exports, module) {
var $ = require('jquery.js')
$('div').addClass('active');
});
// 加载模块
seajs.use(['myModule.js'], function(my){
});
function(require, exports, module)
1、require 是一个方法,接受 模块标识 作为唯一参数,用来获取其他模块提供的接口:require(id)
2、exports 是一个对象,用来向外提供模块接口
3、module 是一个对象,上面存储了与当前模块相关联的一些属性和方法
AMD与CMD区别
同:都是异步加载模块
AMD:在加载模块完成后就会执行改模块,所有模块都加载执行完后会进入require的回调函数,执行主逻辑,**这样的效果就是依赖模块的执行顺序和书写顺序不一定一致**,看网络速度,哪个先下载下来,哪个先执行,但是主逻辑一定在所有依赖加载完成后才执行
CMD:加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,**这样模块的执行顺序和书写顺序是完全一致的**
八、Es6模块化规范
es6在看到这一现状的时候,终于出了模块化开发的规范,那就是export、import。 使用import 代替require,export代替module.exports。
import React from 'react';
class Breadcrumbs extends React.Component {
render() {
return <nav />;
}
};
export default Breadcrumbs;
export导出可以有两种方式,命令式导出和默认导出
1、export { name1, name2, …, nameN };
import {name1, name2} from 'my-module';
命令式导出可以导出多个模块,同时引入也需要指定相应模块名字。
2、export default name1;
import sss from ‘my-module’;
默认导出只可以导出一个模块,但是可以重写模块名字。
九、模块化需要满足的功能及条件
1、模块自身的作用域与用户当前作用域互相独立,也就是插件内部私有变量不能影响使用者的环境变量。
2、模块需具备默认设置参数。
3、模块除了具备已实现的基本功能外,需提供部分API,使用者可以通过该API修改插件功能的默认参数,从而实现用户自定义插件效果。
4、插件支持链式调用。
5、插件需提供监听入口,及针对指定元素进行监听,使得该元素与插件响应达到插件效果。