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
}