JavaScript modules 模块化

206 阅读2分钟

模块化的背景

Javascript 程序本来很小——在早期,它们大多被用来执行独立的脚本任务,在你的 web 页面需要的地方提供一定交互,所以一般不需要多大的脚本。过了几年,我们现在有了运行大量 Javascript 脚本的复杂程序,还有一些被用在其他环境。所以近年来,我们需要考虑一种将 JavaScript 程序拆分为可按需导入的单独模块的机制(选自MDN)

模块化要解决的问题

  1. 加载顺序
  2. 污染全局

原始的写法(立即执行函数)

使用"立即执行函数"(Immediately-Invoked Function Expression,IIFE),可以达到不暴露私有成员的目的。

var moduleA = (function(mod){
    //这里通过参数的形式注入了其他的模块
    var count_a = 0;
    function m1() {
        //...
    };
    function m2() {
        //...
    }
    return {
        m1: m1,
        m2: m2
    }
})(moduleB);

Node.js模块化机制(commonJS)

node.js的模块系统,就是参照CommonJS规范实现的。在CommonJS中,有一个全局性方法require(),用于加载模块。假定有一个数学模块math.js,就可以像下面这样加载。

const math = require('math');
math.add(2,3);   //5

这里第二行的math.add(2,3)需要等到第一行的require('math')的math.js加载完成后才能执行,也就是说如果加载时间很长的话,整个应用就会停留在那里等。

AMD

  1. 异步加载
  2. 管理模块之间的依赖性,便于代码的开发与维护
  3. 使用场景: 浏览器环境
  4. 用法(require.js):
    • 导出define(function(){return {}});
    • 导入require(['模块名称'], function('模块变量应用'){...})
//moduleA.js
define(function() {
    return {
        a: 1,
        b: 2
    }
})

//b.js
require(['./a.js'],function(moduleA){
    console.log(moduleA.a, moduleA.b);
})

CMD

CMD是在AMD基础上改进的一种规范,和AMD不同在于对依赖模块的执行时机处理不同,CMD是就近依赖,而AMD是前置依赖。

AMD与CMD的区别

最明显的区别就是在模块定义时对依赖的处理不同

  1. AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
  2. CMD推崇就近依赖,只有在用到某个模块的时候再去require AMD和CMD最大的区别是对依赖模块的执行时机处理不同

ESM(ES6 Module)

  1. 按需加载
  2. import和export命令只能在模块的顶层,不能在代码块之中(如:if语句中),import()语句可以在代码块中实现异步动态按需动态加载
  3. 适用环境: 浏览器
  4. 使用:
//导出
export const a = 1;

export default {
    a: 1
}

//导入

import { a } from './a.js'
import moduleA from './a.js'