聊一聊模块化(二)原理篇

上一篇介绍了模块化的历史进程以及各个模块化规范的优缺点。而这一篇,主要从模块化规范的实现原理出发,让大家能够更加了解其底层实现,从而应用起来更加得心应手。了解其原理还是有一定必要的,除了能更好的掌握外,更重要的是锻炼自己的思维能力。下面就简单介绍一下模块化规范的原理。

聊一聊模块化(一)简介篇

CommonJS

对于 CommonJS 规范,最重要的就是 require 方法,我们需要带着几个问题去了解 require 的原理实现:

  • 当我们引入一个模块的时候,我们究竟做了怎样一件事情?
  • exports 和 module.exports 有什么联系和区别?

在文档中,有简易版的 require 的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function require(/* ... */) {
// exports 是 module 中的一个属性
const module = { exports: {} };

((module, exports) => {
// 这里的 exports 实际上只是 module.export 的引用
function someFunc() {}

// 直接修改exports 的值,实际上 module.export 中仍然是空对象,导出的是空对象
exports = someFunc;

// 而直接修改 module.export 的值是有效的
module.exports = someFunc;

})(module, module.exports);

return module.exports;
}

(1)require 相当于把被引用的 module 拷贝了一份到当前 module 中

(2)export 实际上是 module.exports 的引用

作为一个引用,如果我们修改它的值,实际上修改的是它对应的引用对象的值。但是如果我们修改其引用地址,对于其原来的内容并不会有影响,反而切断了与 module.exports 的联系。

1
2
3
4
5
6
7
8
9
10
11
exports.a = 1
// 等同于
module.exports = {
a: 1
}


exports = {a: 1}
// 相当于
let other = {a: 1} // 为了更加直观,我们这样声明了一个变量
exports = other // 此时 exports 指向 other

AMD

AMD 规范中的核心就是 define 和 require 方法,下面来看看这两个方法的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
(function(global){
var modules = {};
// 定义模块
var define = function (id,factory) {
if(!modules[id]){
modules[id] = {
id : id,
factory : factory
};
}
};
// 引入模块
var require = function (id) {
var module = modules[id];
if(!module){
return;
}

if(!module.exports){
module.exports = {};
module.factory.call(module.exports,require,module.exports,module);
}

return module.exports;
}

global.define = define;
global.require = require;
})(this);

参考

  • Javascript 模块化管理的来世今生
  • 从 IIFE 聊到 Babel 带你深入了解前端模块化发展体系