模块化开发(一)

什么是模块化

将一组模块(及其依赖项)以正确的顺序拼接到一个文件(或一组文件)中的过程。javascript

传统的模块化作法。

模块是实现特定功能的一组属性和方法的封装。html

将模块写成一个对象,全部的模块成员都放到这个对象里面。java

var module1 = new Object({
  _count:0,
  f1:function(){},
  f2:function(){}
})
module1.f1()
module1.f2()

上面的对象能够改变里面的属性和方法,不安全git

var module1 = (function(){
 var count=0;
 return { 
   f1:function(){},
  f2:function(){}}
}());
module1.f1()
module1.f2()
module1.count //undefined

使用 将相应的方法和属性封装在函数中,这样就不会暴露私有成员es6

利用构造函数封装对象

function Father (){
  var arr =[];
  this.add = function (val){
       arr.push(val)
  }
  this.toString = function(){
    return arr.join('');
  }
}
var a = new Father();
a.add(1);//[1]
a.toString();//"1"
a.arr // undefined

上面的函数将 arr 变成私有变量,在函数外部没法访问,可是造成了闭包,很是耗费内存;
违背了构造函数与实例对象在数据上相分离的原则(即实例对象的数据,不该该保存在实例对象之外)。github

function ToString() {
  this._buffer = [];
}

ToString.prototype = {
  constructor: ToString,
  add: function (str) {
    this._buffer.push(str);
  },
  toString: function () {
    return this._buffer.join('');
  }
};

虽然上面的构造函数未生成闭包,可是外部能够修改方法和属性,不安全数组

放大模式

若是一个模块很大或者一个模块须要继承另外一个模块能够利用当即执行函数的特效来封装浏览器

var module1 = (function(m1){
mod1.col=function(){
  console.log(this)
};
return mod1;
}(window.modlue2 ||{})) //有些模块多是null 确保函数正常执行 采用兼容模式 window.modlue2 ||{}
  • 独立性是模块的重要特色,模块内部最好不与程序的其余部分直接交互。
var module1 = (function ($, Swiper) {
 //...
}(jQuery, Swiper));

上面的 module1 引入 jQuery 和 Swiper 当作两个参数传入模块中,保证了模块的独立性,还使得模块之间的依赖关系变得明显。缓存

当即执行函数还能够起到命名空间的做用。安全

(function($, window, document) {

  function go(num) {
  }

  function handleEvents() {
  }

  function initialize() {
  }

  function dieCarouselDie() {
  }

  //attach to the global scope
  window.finalCarousel = {
    init : initialize,
    destroy : dieCarouselDie
  }

}( jQuery, window, document ));

以上都有一个共同点:使用单个全局变量箭头代码包装在函数中,使用闭包创建私有空间
可是都有缺点:

  • 不知道模块(库) 的加载顺序
  • 仍是有可能引发命名冲突,好比两个库都有相同的名称,或者使用哪一个版本
    有几种良好实施的方法:CommonJS、AMD和CMD。能够解决以上的缺陷

CommonJS

  • CommonJS 是一种思想, 本质上是可复用的JavaScript,它导出特定的对象,提供其它程序使用。

  • 因为 JavaScript 没有模块系统、标准库较少、缺少包管理工具,所以CommonJS是为它的表现来制定规范。

  • 每一个JavaScript 文件 都将模块存储在本身独有的做用域中。

  • 须要使用 module.exportsexports.obj 来导出对象,并在须要它的程序中使用 require('module') 加载

//文件1
function myModule() {
 this.hello = function() {
   return 'hello!';
 }

 this.goodbye = function() {
   return 'goodbye!';
 }
}

module.exports = myModule;


//文件2
var myModule = require('myModule');

var myModuleInstance = new myModule();
myModuleInstance.hello(); // 'hello!'
myModuleInstance.goodbye(); // 'goodbye!'

实现原理

var module1 = { 
   export1:{}
 };

 (function (module,exports){
    exports.add = functon(val){
       return val *10
    }
 }(module1,module1.export1));

 var fn = module1.export1.add;
 fn(2)//20

利用当即执行函数 接受两个参数 module 和 exports, 模块就经过当即执行函数赋值,而后导出模块,便可实现模块的加载
这种方法的好处:

  • 避免全局污染
  • 明确依赖项目
  • 语法清晰
    缺点:
  • 因为 CommonJS 采用服务器优先方法而且同步加载模块,所以在浏览器中使用它会阻止浏览器运行其余内容,直到加载完成。

咱们可使用 AMD 来异步加载

AMD(Asynchromous Module Definition)

  • 定义了一套 JavaScript 模块依赖异步加载标准,来解决同步加载的问题。
  • AMD模块加载不影响后面语句的运行。全部依赖某些模块的语句均放置在回调函数中。
  • 定义了一个函数 define,经过 define 方法定义模块。
define(['myModule', 'myOtherModule'], function(myModule, myOtherModule) {
 console.log(myModule.hello());

});

上面的 define 函数将每一个模块的依赖项,以数组的形式做为参数。

这些依赖项会在后台异步加载,一旦加载完成,define 函数就调用模块给出的回调函数
myModule 可能像下面同样定义:

define([], function() {

  return {
    hello: function() {
      console.log('hello');
    },
    goodbye: function() {
      console.log('goodbye');
    }
  };
});

CMD(Common Module Definition)

  • CMD由玉伯大佬提出并用于SeaJS
  • CMD 和 AMD 很类似,都有 define 函数, 经过 require 加载

CMD和AMD 不一样点:

  • 对于依赖的模块 CMD 延迟执行, AMD 提早执行(requireJS 高版本也开始延迟执行)
  • CMD使用依赖就近原则(按需加载):
define(function(require, exports, module) {   
         var near = require('./a')   
         near.doSomething()   
         // 此处略去 100 行  
          var nearOne = require('./b') // 依赖能够就近书写   
          nearOne.doSomething()   // ...
           })
  • AMD使用依赖前置原则(必须先加载完依赖):
define(['./a', './b'], function(nearTow, nearThree) { // 必须一开始加载
           nearTow.doSomething()
           // 此处略去 100 行
           nearThree.doSomething()
           ...
           })
  • CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每一个 API 都简单纯粹。 AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。好比 AMD 里,require 分全局 require 和局部 require,都叫 require。

AMDCommonJS 不一样点:

AMD

  • 采用浏览器优先的方法,异步加载,主要用于浏览器
  • 先加载依赖项
  • 依赖项能够说 对象、函数、构造函数、字符串等等其余JS类型

CommonJS:

  • 采用服务器优先的方法,同步加载,主要用于服务器
  • 支持对象做为模块
    共同点: 先加载依赖项

通用模块定义 UMD

同时支持 AMDCommonJS
本质 建立了一种方法来使用二者的任何一种,同时支持全局变量定义,(JS兼容性的经常使用思想)因此 UMD 能够在客户端和服务器上工做

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
      // AMD
    define(['myModule', 'myOtherModule'], factory);
  } else if (typeof exports === 'object') {
      // CommonJS
    module.exports = factory(require('myModule'),
     require('myOtherModule'));
  } else { 
    root.returnExports = factory(root.myModule, root.myOtherModule);
  }
}(this, function (myModule, myOtherModule) {
  function notHelloOrGoodbye(){}; 
  function hello(){}; 
  function goodbye(){}; 
  return {
      hello: hello,
      goodbye: goodbye
  }
}));

ES6模块(即 ES2015/ECMAScript 六、ES6

  • 使用 import 关键字引入模块,经过 export 关键字导出模块
  • ES6目前没法在浏览器中执行,只能经过babel将不被支持的import编译为当前受到普遍支持的 require。
//a.js
export let cun =1; 
export function add() {
  cun++;
}
//----------------
import { cun, add } from './a.js';
console.log(cun); // 1
incCounter();
console.log(cun); // 2
export var fo ='a';
setTimeout(() => fo ='b',500);

import {fo} from './a.js';
console.log(fo);//'a'
setTimeout(()=> console.log(fo),500)//'b'

//ES6 输入的模块变量,只是一个“符号链接”,因此这个变量是只读的,对它进行从新赋值会报错。
fo = 's' //error
  • ES6 模块之中,顶层的this指向undefined,即不该该在顶层代码使用this。
    CommonJSAMDCMD相比:
  • ES6模块是动态引用,而且不会缓存值,模块里面的变量绑定其所在的模块。
  • ES6 对外接口只是一种静态定义,在代码静态解析阶段就会生成。
  • ES6 module编译时输出接口(加载),输出的是值的引用。(静态编译)
  • CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。
  • CommonJS 模块运行时加载,输出的是一个值的拷贝。(动态编译)
    一旦输出一个值,模块内部的变化就影响不到这个值。
// lib/counter.js

var counter = 1;

function increment() {
  counter++;
}

function decrement() {
  counter--;
}

module.exports = {
  counter: counter,
  increment: increment,
  decrement: decrement
};


// src/main.js

var counter = require('../../lib/counter');

counter.increment();
console.log(counter.counter); // 1

模块化开发(二)

相关文章
相关标签/搜索