为什么要有模块化?
-
项目庞大时,js文件多,变得不好维护
-
js文件作用域都是顶层,这会造成变量污染
-
js文件依赖问题,稍微不注意顺序引入错,代码全报错
CommonJS
CommonJS
是一个更偏向于服务器端的规范。NodeJS
采用了这个规范。CommonJS
的一个模块就是一个脚本文件。require
命令第一次加载该脚本时就会执行整个脚本,然后在内存中生成一个对象缓存下来,后面再加载就不用执行脚本了。
// ./common.js
const fn = () => console.log(1);
const COLORS = ['red', 'blue', 'green'];
module.exports = {
fn,
COLORS,
};
// -----
// ./index.js
const common = require('./common.js');
common.fn();
common.COLORS;
在模块化规范 CommonJS
中,通过 require
、exports
引入/导出 模块。其中 require
的底层实现为一个 匿名函数自调用(闭包)。模块化要解决的一个核心问题就是 变量名污染。闭包就可以解决这个问题。
const m = (function() {
const fn = () => console.log(1);
const COLORS = ['red', 'blue', 'green'];
return {
fn,
COLORS,
};
})();
- 使用node的fs模块和path读取对应文件的内容
- 通过字符串拼接将,fs读取到的字符串拼接起来的,构成该自执行函数
- 使用vm模块构建一个沙箱环境,执行该自执行函数
- 返回module.exports,将模块内容返回
const fs = require('fs');
const path = require('path');
const vm = require('vm'); // 虚拟机,提供沙箱环境
const wrapper = [
'(function(exports, module, require){',
'})'
]
function Module(absPath) {
this.id = absPath; // 存储当前路径
this.exports = {};
}
Module.prototype.load = function() {
let script = fs.readFileSync(this.id, 'utf8');
let fnStr = wrapper[0] + script + wrapper[1];
let fn = vm.runInThisContext(fnStr); // 沙箱执行当前函数
fn(this.exports, this, req); // 让拼出的函数执行
}
function req(file ) {
let absPath = path.resolve(__dirname, file); // 1. 获取文件路径
let module = new Module(absPath); // 2. 创建一个模块
module.load(); // 3. 加载方法
return module.exports;
}
let a = req('./a.js')
AMD
AMD
采用异步加载模块,模块加载不影响后面代码执行。依赖该模块的代码写到回调函数中。
模块引入
require(['math'], function(math) {
// 依赖 math 模块的代码
math.add(1, 2);
});
console.log('xx'); // 不受上面模块加载影响
模块导出
// math.js
define(function() {
const add = (x, y) => x + y;
return {
add,
};
});
// or
define(['other'], function(other) { // 当前导出的模块还可以依赖其他模块 other
const add = (x, y) => x + y;
return {
add,
};
});
主模块统一调度
// main.js
(function () {
require.config ({
// baseUrl:'',
paths:{
dataService:'./dataService',
math:'./math',
other: './other',
}
})
require(['dataService'], function (dataService) {
dataService.doSomething()
});
})();
ES6 Module
ES6 Module 是静态的,在编译的时候确定模块间的依赖关系。所以 import xx from 'xx'
引入只能声明在文件顶部,不能动态加载。
// ./common.js
export const TYPES = [1, 2, 3];
export const MAX = 9999;
const obj = {
name: 'leonsux',
age: 26,
}
export default obj
import obj, { TYPES, MAX as _MAX } from './common.js';
相关文档
https://www.jianshu.com/p/c7ad410e6667
https://www.cnblogs.com/echoyya/p/14577243.html
https://juejin.cn/post/6938581764432461854