JavaScript 模块化

1,114 阅读3分钟

什么是模块化,为什么要模块化?回答这个问题需要了解前端的发展历史,我们从 前端发展早期前端进入服务器时代前端发展繁荣时期 来了解 JavaScript 模块化。

前端发展早期

那个时候业务非常简单,可能就处理一些点击、弹框、表单提交等逻辑,在页面中通过 script 标签引入一个 JS 文件就搞定了

<!-- index.html -->
...
<script src="main.js"></script>
...

即使业务复杂一点的,多引入几个 JS 文件也可以搞定

<!-- index.html -->
...
<script src="main.js"></script>
<script src="a.js"></script>
<script src="b.js"></script>
...

但需要注意引入顺序,以及命名空间污染等问题。

前端进入服务器时代

由Ryan Dahl开发,2009年5月发布的 Node.js 让 JS 不仅仅运行在浏览器端,也可以在服务器端运行。

这也带来一个问题,由于服务器的复杂性,代码量巨大,所以需要一个机制来管理这些代码。

这个机制需要具备三个方面能力:

  • 代码可维护性: 不相干的代码是相互独立模块,每个模块的升级或者重构不会影响其他的模块
  • 解决命名空间污染的问题: 不相干的代码他们的命名,即使相同也不能相互冲突
  • 代码复用能力: A 文件的代码,需要用到 B 文件的方法,不是粗暴的粘贴复制,而是直接引用 B 的方法就可以了,以后重构优化就不需要每个文件去改。

Common.js 应运而生,用于处理 Node.js 的代码管理。

// a.js
var a = {}
module.export = a

// b.js
var a = require('./a')

由于 Node.js 是在服务器端运行的,操作本地磁盘,延迟低,所以 Common.js 是同步引入的。

前端发展繁荣时期

随着互联网的高速发展,前端复杂度越来越高,很多时候并不亚于后端,所以也需要 Common.js

browserify 让浏览器端也可以用Common.js

先安装 browserify:

npm install -g browserify
// main.js
var add = require('./a.js')
console.log(add(1,2))

// a.js
var add = function(){ return a+b }
module.exports = add
browserify main.js -o bundle.js

script 标签直接引入 bundle.js 就可以用了。

bundle.js 代码中我们可以看到,Common.js 创建了文件依赖关系和相互独立的命名空间:

(function() {
  function r(e, n, t) {
    function o(i, f) {
      ...
      ...
    }
  }
})()(
  {
    1: [
      function(require, module, exports) {
        var add = function(a, b) {
          return a + b;
        };
        module.exports = add;
      },
      {}
    ],
    2: [
      function(require, module, exports) {
        var add = require("./a.js");

        console.log(add(1, 2));
      },
      { "./a.js": 1 }
    ]
  },
  {},
  [2]
);

由于 Common.js 同步的特性,如果 var add = require('./a.js') 需要执行很长时间,这时候浏览器就会假死,所以浏览器需要异步执行,Common.js 并不满足,AMD 应运而生。

AMD

AMD 全称是 Asynchronous Module Definition,从名字就可以看出,它最大的特色就是异步。具体用法:

define(['aModule', 'bModule'], function(aModule, bModule) {
  console.log(aModule.hello());
});

aModulebModule 加载完毕后,再会执行后面的回调,从而实现异步的能力。

实现 AMD 规范的有: require.js

ES Module

浏览器除 AMD 外,还有 CMD(主要区别:AMD 预加载,CMD 懒加载)等规范,为统一浏览器模块化规范,以及浏览器端和服务器端的大统一,ECMA 制定了 ES Modules 规范:

// a.js
export function add() {return a+b}

// b.js
import {add} from a
add(1,2)

从此以后,开发者在开发工具或者框架时,就不用再兼容各种模块化规范了。

Reference