js模块化笔记

CommonJS

CommonJS是一种使用广泛的JavaScript模范化管理,核心思想是通过require方法来同步地加载依赖的其他模块,通过module.exports导出需要暴露的接口

用法

采用CommonJS导入及导出时的代码如下:

// 导入
const A = require('./a.js');
fn();
// 导出
module.exports = A.fn;
原理实现
// a.js
module.exports = '刚好遇见你';

//b.js
const fs = require('fs');
// CommonJS简单实现
function req(pathName) {
    // content代表的是文件内容
    let content = fs.readFileSync(pathName, 'utf8');
    // 最后一个参数是函数的内容体
    let fn = new Function('exports', 'require', 'module', '__filename', '__dirname', content+'\n return module.exports');
    let module = {
        exports: {}
    };
    // 函数执行就可以取到module.exports的值了
    return fn(module.exports, req, module, __filename, __dirname);
}
const str = req('./a.js');  // 导入a模块
console.log(str);   // '刚好遇见你'

AMD

AMD也是一种JavaScript模块化规范,与CommonJS最大的不同在于它采用异步的方式去加载依赖的模块。 AMD规范主要是为了解决针对浏览器环境的模块化问题,最具代表性的实现是RequireJS

AMD的优点

  • 可在不转换代码的情况下直接在浏览器里运行
  • 可加载多个依赖
  • 代码可运行在浏览器环境和Node环境中

AMD的缺点

  • Js运行环境没有原生支持AMD,需要先导入实现了AMD的库才能正常使用(这里指的是RequireJS)
用法
// define定义模块
define('song', [], () => {
    return '告白气球';
});
define('singer', ['song', 'album'], (song, album) => {  // 依赖了song和album模块
    let singer = '周杰伦';
    return `${singer}的${song}属于专辑《${album}》`;
});
define('album', [], () => {
    return '床边故事';
});
// require使用模块
require(['singer'], singer => {
    console.log(singer);   // 周杰伦的告白气球属于专辑床边故事
});
原理实现

RequireJS有两个方法,一个是define,另一个是require,所以首先我们先定义两个函数,看如下代码

let factories = {};     // 管理一个关联对象,将模块名和函数关联起来
// 定义模块define  三个参数:1.模块名 2.依赖 3.工厂函数
function define(name, depend, factory) {
    factories[name] = factory;
    factory.depend = depend;    // 将依赖记到factory上
}
// 通过require使用模块
function require(modules, callback) {
    let result = modules.map(mod => {   // 返回一个结果数组
        let factory = factories[mod];   // 拿到模块对应的函数
        let exports;
        let depend = factory.depend;    // 取到函数上的依赖 ['a']
        
        // require(['song','album'], function(song,album) {})  可能会有很多依赖
        require(depend, () => {         // 递归require
            exports = factory.apply(null, arguments);
        });
        return exports;     // exports得到的是函数返回的值  如:'告白气球' , ' 床边故事'
    });
    callback.apply(null, result);   //  result为一个结果数组,所以用apply
}