为什么有模块化
- 1.方便代码维护
- 2.每个功能放到一个模块内
- 3.解决命名问题,全局变量污染问题
常见的模块化
- 1.我们写方法写属性都放在对象里(单例模式)
- 缺陷声明的对象也有可能命名冲突,不能完全解决上述问题
var obj = {
a:1,
init(){
}
fn(){
}
}
复制代码
- 2.自执行函数(IIFE) 实现模块化的功能,要把最终的结果对外暴露
- 好处
- 1.没有名字
- 2.有自己单独的执行作用域
- 3.可以对外暴露一些属性
- 缺陷
- 浏览器的文件加载(http请求),异步的问题不易解决
- 好处
(function(){
...;
return XXX
})()
复制代码
commonjs规范定义了几个点(同步的)
- 1.如何声明一个模块,node中一个文件就是一个模块
- 2.每个模块都需要导出最终的结果
module.exports
- 3.每个模块使用其他模块的时候需要使用
require
方法
commonjs的实现流程
就是把文件读取出来之后加一个 函数 执行 最终返回的是
module.exports
- 1.每个模块都有一个
require
方法-->Module.prototype.require
- 2.调用
Module._load()
加载模块 - 3.调用
Module._resolveFilename()
解析出文件的绝对路径,并且增加拓展名 - 4.通过
Module._cache[filename]
检查是否存在缓存,如果有直接返回缓存模块的module.exports
- 5.检查是否是内置模块(例如
fs
模块),如果不是,通过new Module(filename)
创建一个模块,模块上有两个重要的属性id
&&exports = {}
- 6.将创建的模块放到缓存中
Module._cache[filenama] = module
- 7.尝试加载模块
tryModuleLoad(module, filename)
核心- 1).通过
path.extname(filename)
获取文件的扩展名extension
- 2).通过扩展名
extension
去Module._extensions
中找相应的方法读取文件content
- 3).通过
Module.wrap(content)
方法将读取到的内容进行包装,返回包装后的结果wrapper
- 4).通过
vm.runInThisContext(wrapper)
返回一个可执行函数compiledWrapper
- 5).
compiledWrapper.call(this.exports, this.exports, require, this, filename, dirname)
执行
- 1).通过
let path = require('path');
let fs = require('fs');
let vm = require('vm');
function req(pathname) {
return Module._load(pathname);
}
function tryModuleLoad(module, filename) {
return module.load(filename);
}
function Module(id) {
this.id = id;
this.exports = {};
}
Module.prototype.load = function (filename) {
let extension = path.extname(filename);
Module._extensions[extension](this);
return this.exports;
}
Module._extensions = {
'.js': function (module) {
let content = fs.readFileSync(module.id, 'utf8');
let wrapper = Module.wrap(content);
let compiledWrapper = vm.runInThisContext(wrapper);
let result = compiledWrapper.call(module.exports, module.exports, req, module)
Module._cache[module.id] = result;
},
'.json': function (module) {
let result = JSON.parse(fs.readFileSync(module.id, 'utf8'));
Module._cache[module.id] = result;
module.exports = result;
}
}
Module._cache = {};
Module._load = function (pathname) {
let filename = Module._resolveFilename(pathname);
let cacheModule = Module._cache[filename];
if (cacheModule) return cacheModule.exports;
/* 此处略掉检查内部模块 */
let module = new Module(filename);
return tryModuleLoad(module, filename);
}
Module._resolveFilename = function (pathname) {
let absName = path.resolve(__dirname, pathname);
try {
fs.accessSync(absName);
} catch (err) {
let extArr = ['.js', '.json'];
let ext = path.extname(absName);
if (!ext || !extArr.includes(ext)) {
extArr.every((extname, index) => {
let spliceName = absName + extname;
try {
fs.accessSync(spliceName);
absName = spliceName;
return false;
} catch (err) {
if (index == 1) {
throw new Error(`${pathname} is not defined`)
}
return true
}
})
} else {
throw new Error(`${pathname} is not defined`)
}
}
return absName
}
Module.wrap = function (content) {
return Module.wrapper[0] + content + Module.wrapper[1];
}
Module.wrapper = ['(function (exports, require, module, __filename, __dirname) {', '});']
let r = req('./user');
console.log(r);
复制代码