JS模块化专题二

NodeJS 模块化体验

NodeJS诞生带来前所未有的模块化体验,不在需要html导入JS,真正实现JS模块之间的相互独立与依赖。

require('......'); // 引入模块
module.exports // 导出模块

CommonJS 实现

module_a.js

var a = (function () {
  return [1, 2, 3, 4, 5].reverse();
})();

module.exports = {
  a
}

module_b.js

var moduleA = require('./module_a') ;

var b = (function () {
  return moduleA.a.concat([6, 7, 8, 9, 10]);
})();

module.exports = {
  b
}

module_c.js

import moduleB = require('./moduleB');

var c = (function () {
  return moduleB.b.join('-');
})();

module.exports = {
  c
}

index.js

import moduleA require('./moduleA');
import moduleB require('./moduleB');
import moduleC require('./moduleC');

console.log(moduleA.a);
console.log(moduleB.b);
console.log(moduleC.c);

关于CommonJS

CommonJS是一种模块化规范,不是JS方法集合、JS库等;
CommonJS规范来源于NodeJS;
CommonJS使用的方法,实际是同步方法,文件加载是同步进行的;

CommonJS使用require关键字,只要引用,就会创建一个模块实例(实例化);
CommonJS存在缓存机制,只要require导入,模块就会被缓存,不会多次进行导入;
CommonJS是在Node环境中运行的,客户端环境无法运行;

require在引用后实质是一个立即执行函数。

;(function (exports, require, module, __filename, _dirname) {

})();

AMD

客户端的”CommonJS” - AMD,但两者只是表面上相似;
CommonJS是同步模块定义,AMD是异步模块定义(Asynchronous Module Definition);
RequireJS是AMD规范的实现,AMD规范是由RequireJS实现的,可以实现异步加载模块;
AMD不支持浏览器,不需要运行在node环境,也不需要运行在webpack中;

define(moduleName, [module], factory); // 定义模块
require([module], callback); // 引入模块

AMD是所有模块加载完毕,才会执行回调函数,是前置依赖,即依赖前面的模块;
不会考虑模块的加载顺序问题,解决模块加载顺序问题;
规范了模块的输入与输出,实际是用async的方式异步加载模块;

RequireJS

module_a.js

define('moduleA', function () {
  var a = [1, 2, 3, 4, 5];

  return {
    a: a.reverse()
  }
});

module_b.js

define('moduleB', ['moduleA'], function (moduleA) {
  var b = [6, 7, 8, 9, 10];

  return {
    b: moduleA.a.concat(b)
  }
});

module_c.js

define('moduleC', ['moduleB'], function (moduleB) {
  return {
    c: moduleB.b.join('-')
  }
});

index.js

// 配置路径
require.config({
  paths: {
    moduleA: 'js/module_a',
    moduleB: 'js/module_b',
    moduleC: 'js/module_c'
  }
})

// 所有模块加载完毕,才会执行回调函数
require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC) {
  console.log(moduleA.a);
  console.log(moduleB.b);
  console.log(moduleC.c);
});

index.html

<script type="text/javascript" src="js/require.js" />
<script type="text/javascript" src="js/index.js" />

CMD

阿里也为模块化做了贡献-CMD

通用模块定义(Common Module Definition)

浏览器同样不支持CMD规范,使用SeaJS框架实现

define(function (require, exports, module) {}); // 定义模块
seajs.use([module路径], function (moduleA, moduleB, moduleC) {}); // 使用模块

CMD require 引入模块、define 定义模块
exports 导出模块、module 操作模块

使用模块时,需要配置模块URL;
依赖加载完毕后执行factory;

CMD是依赖就近,按需加载模块,与CommonJS、AMD有本质区别;
AMD是依赖前置,CMD是需要的时候去加载模块;

SeaJS

module_a.js

define(function (require, exports, module) {
  var a = [1, 2, 3, 4, 5];

  return {
    a: a.reverse()
  }
});

module_b.js

define(function (require, exports, module) {
  var moduleA = require('module_a'),
      b = [6, 7, 8, 9, 10];

  return {
    b: moduleA.a.concat(b)
  }
});

module_c.js

define(funvtion (require, exports, module) {
  var moduleB = require('module_b');

  return {
    c: moduleB.b.join('-')
  }
});

index.js

seajs.use(['module_a.js', 'module_b.js', 'module_c.js'], function (moduleA, moduleB, moduleC) {
  console.log(moduleA.a);
  console.log(moduleB.b);
  console.log(moduleC.c);
});

index.html

<script type="text/javascript" src="js/sea.js" />
<script type="text/javascript" src="js/index.js" />

ES6 模块化

ES6官方终于给出权威答案 - ES6模块化

import module from '模块路径'; // 导入模块
export module; // 导出模块

module_a.js

export default {
  a: [1, 2, 3, 4, 5].reverse()
}

module_b.js

import moduleA from './module_a';

export default {
  b: moduleA.a.concat([6, 7, 8, 9, 10])
}

module_c.js

import moduleB from './module_b';

export default {
  c: moduleB.b.join('-')
}

index.js

import moduleA from './module_a';
import moduleB from './module_b';
import moduleC from './module_c';

console.log(moduleA.a);
console.log(moduleB.b);
console.log(moduleC.c);

commonJS 与 ES6

export.js

exports.a = 0;

setTimeout(() => {
  console.log('来自export', ++exports.a); // 1
}, 300);

common.js

const { a } = require('./export');

setTimeout(() => {
  console.log('来自commonjs', a); // 0
}, 500);

es6.js

import { a } from './export';

setTimeout(() => {
  console.log('来自ES6', a); // 1
}, 500);

ES6与CommonJS区别

  1. commonjs 模块输出的是一个值的拷贝;
    es6 模块输出的是值的引用;
  2. commonjs 模块是在运行时加载;
    es6 模块是在编译时加载;