前言
本文是Node系列
的require篇
之前学模块化的时候就接触到这个require了,现在重温Node系列,又遇到了这个。
想着,应该有些小伙伴挺感兴趣的,索性就把笔记更新到这里吧~~~
正文开始
1,require是基于CommonJS实现的
工欲善其事必先利其器
,先了解下CommonJS
是什么东西吧
require
的实现基于CommonJS规范
,属于模块化规范的一种,对模块化规范的发展史
有兴趣的小伙伴,# 浅谈模块化,小白看完也能恍然大明白
此处和小伙伴简单聊一下~~~
1.1,模块化是技术不断更迭的产物,核心是解决两个问题
-
隔离变量:每个模块有其独立作用域
-
相互通信:模块之间通过modules,modules.exports暴露了入口,可以互相通信
1.2,模块化规范的优点:让复杂项目或者功能的开发变得更简单。
-
使用网上前辈们开发好的轮子更方便了
-
可以对复杂项目的开发流程进行碎片化分解,各自为战,提高开发效率和可读性(一个小功能一个页面,读起来可太方便了)(呃~~~也不宜过于碎片化)
1.3,模块化的发展史
1,作用域让变量隔离:bar的作用域只限于foo函数之中,外面是访问不到的
js
function foo() {
var bar = 1;
var baz = 2;
}
2,访问函数里的变量:obj.a可以访问到resolve函数中过的bar了
js
var obj = {
a: {
}
};
function resolve(a) {
var bar = 1;
var baz = 2;
a = {
bar, baz
}
}
resolve(obj.a)
3,CommonJS规范雏形出来了
js
var module = {
exports: {
}
};
function resolve(module, exports) {
var bar = 1;
var baz = 2;
module.exports = {
bar, baz
}
}
resolve(module, module.exports)
踩坑:上面的第10行
使用module.exports
而不直接用exports
的原因是为了保持引用关系
不被打破。
2,require函数的简易实现
index.js
js
console.log('hello world')
require.js
js
// const xxx = require('xxx.js')
const { readFileSync } = require("fs");
const { resolve } = require("path");
const { Script } = require("vm");
function my_require(filename) {
const fileContent = readFileSync(resolve(__dirname, filename), 'utf-8');
const warpped = `(function(require, module, exports) {
${fileContent}
})`
const scripts = new Script(warpped, {
filename: 'index.js',
})
const module = {
exports: {}
}
const func = scripts.runInThisContext();
func(my_require, module, module.exports);
return module.exports;
}
global.my_require = my_require;
my_require('./index.js');
2.1,核心点解析
1,代码中的fs
,path
,vm
是node
这个宿主环境提供的API,可以直接使用。
-
fs path: 操作磁盘
-
vm: Node.js 的虚拟机模块,它提供了一种在 V8 虚拟机环境中执行 JavaScript 代码的机制。
这个宿主环境,小伙伴们可以类比浏览器,比如chrome浏览器也是一个宿主环境,它提供了document, window等Api可以操作DOM等功能
关于node
的相关知识点,我会另开一篇文章,到时候会贴到这里 => 占位
2,readFileSync
fs
模块提供的方法,用于读取文件内容
readFileSync(resolve(文件路径
, 文件名
), 确定编码格式输出文件内容
);
3,warpped
打印出来的内容如下图:
4,第13-15行:new Script
创建一个叫index.js
的脚步文件对象,脚本对象包含了 warpped
中的代码。此处的index.js
可不写,可随便起名
5,第21行:runInThisContext
vm
模块提供的方法,用于在当前的上下文中运行
之前创建的脚本文件,生成一个fun函数
(此时,fuc函数还没被执行)
第4小点 + 第5小点等于是定义了一个func函数,函数体就是上面warpped
打印的内容
6,为什么9-11行不能写成下面这样呢?
js
const warpped = `function(require, module, exports) { ${fileContent} }`
原因如下图:
上文有说scripts.runInThisContext()
会运行一遍创建好的脚本文件
- 立即执行函数体(上图蓝框)运行后会变成普通函数体。
- 普通函数体(上图黄框)运行后就会报错
完结
这篇文章我尽力把我的笔记和想法放到这了,希望对小伙伴有帮助。
欢迎转载,但请注明来源。
最后,希望小伙伴们给我个免费的点赞,祝大家心想事成,平安喜乐。