⚡node打怪升级系列 - 浅谈require函数

前言

本文是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()会运行一遍创建好的脚本文件

  • 立即执行函数体(上图蓝框)运行后会变成普通函数体。
  • 普通函数体(上图黄框)运行后就会报错

完结

这篇文章我尽力把我的笔记和想法放到这了,希望对小伙伴有帮助。

欢迎转载,但请注明来源。

最后,希望小伙伴们给我个免费的点赞,祝大家心想事成,平安喜乐。

相关推荐
子兮曰4 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰4 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万4 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝4 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋4 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁5 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄5 天前
JavaScript 隐式全局变量解析
javascript
汉堡大王95275 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大5 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师5 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端