随着应用越来越复杂,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、插件需提供监听入口,及针对指定元素进行监听,使得该元素与插件响应达到插件效果。