日常的学习笔记,包括 ES6、Promise、Node.js、Webpack、http 原理、Vue全家桶,后续可能还会继续更新 Typescript、Vue3 和 常见的面试题 等等。
动态模块与静态模块
关于之前文章中 动态静态 的含义。
首先,es6Module属于 "静态模块",commonjs属于 "动态模块"。
静态模块 是可以在编译的时候进行引入分析的,他可以进行 tree-shaking
(webpack打包时自动去掉不用的代码)。而 动态模块 是在代码执行的时候引入模块的,他不可以进行 tree-shaking
。
关于
tree-shaking
,可以参考 Tree Shaking | MDN
文件用webpack打包之后,文件就会从 es6Module规范 转换成 commonjs规范。
模块的规范与分类
首先,我们先回顾一下 commonjs模块规范:
- 每个js 文件都是一个模块。(每个模块外面都有一个函数)
- 模块的导出
module.exports
- 模块的导入
require
而模块中也有自己的分类,下面我们介绍一下 模块分类:
- 核心模块 也叫内置模块,包括
fs
、http
、path
、vm
等等。在使用时 不需要进行安装,直接引入即可。引入的时候也 不需要添加绝对路径或相对路径 。 - 第三方模块 也就是别人定义的模块,像
co
等等。此类模块在使用的时候 需要进行安装。 - 自定义模块 是用户自己封装或定义的模块,在使用的时候需要 通过绝对路径或者相对路径进行引入。
常用的核心模块
fs模块
-
fs.readFileSync
我们先举个 核心模块 的例子。
const fs = require('fs'); // require内部使用的就是readFileSync来实现的 let r = fs.readFileSync('./test.js','utf8'); console.log(r);
首先,
require
是同步方法。假设require
是异步的话,那么每引入一个模块,我们都需要在其成功的回调中写我们下一步需要执行的代码,这样就会造成代码的冗余和堆积。所以
require
的内部就是使用 readFileSync 来实现的。 -
fs.existsSync
我们在读取文件时,如果读取的文件不存在,那么就会发生异常。
let r = fs.readFileSync('./testxxx.js','utf8'); // 假设此文件不存在 console.log(r); // 报错
这时我们可以使用
existsSync
来对文件进行判断。let f = fs.existsSync('./testxxx.txt'); console.log(f); // false
此方法目前只有 同步方法,
异步方法已经被废弃了。
path模块
-
path.resolve
path
模块是专门用来处理路径的。path.resolve
方法会把一个路径或路径片段的序列解析为一个绝对路径。const path = require('path'); console.log(path.resolve('a', 'b', 'c')); // d:\xxx\xxx\xxx\a\b\c
他会将当前绝对路径为前缀,将传入的参数以
\
分割,并解析成新的绝对路径。但是这样会出现一个问题,假设我们现在切换一下执行目录,那么路径就会发生错误。原因是因为
path.resolve
默认采用的解析方式是process.cwd()
。为了使路径正确,我们可以采用以下解决方案。
const path = require('path'); console.log(path.resolve(__dirname ,'a', 'b', 'c', '/')); // 路径回到了根目录下
(注:如果路径中存在
/
,当前路径会回到跟目录下 ) -
path.join
path.join
是将传入的参数进行路径拼接,不会添加任何路径。参数中如果存在
/
,也会被拼接在一起。const path = require('path') console.log(path.join('a', 'b', 'c', '/')); // a\b\c\
所以我们可以使用这种方法进行绝对路径的拼接。
const path = require('path'); console.log(path.join(__dirname ,'a', 'b', 'c', '/')); // 路径被拼接在一起
**在某些情况下,
path.join
和path.resolve
是可以互换使用的。但是在路径中出现/
的情况下,还是使用path.join
更好。 ** -
path.extname
path.extname
会获取文件扩展名,也可以说就是文件的类型。const path = require('path'); console.log(path.extname('text.min.js')); // .js
-
path.basename
path.basename
方法返回path
的最后一部分。const path = require('path'); console.log(path.basename('d:/xxx/xxx/xxx/test.js','.js')); // test
若不传最后一个参数,则会直接返回最后的文件名
test.js
-
path.relative
path.basename
方法会根据当前路径,获取相对路径。const path = require('path'); console.log(path.basename('a/b/c/test.js','a')); // ..\..\..
-
path.dirname
path.dirname
方法会获取当前文件的父路径。const path = require('path'); console.log(path.dirname('a/b/c')); // a/b
__dirname的实现就是用的
path.dirname
。
vm模块
在说这个模块之前,我们可以先思考一个问题。
字符串如何能变成JS执行呢?
-
eval函数
参考文献 eval()函数
我们第一个想到的就是
eval()
函数,他可以将传入的字符串或表达式转换成可以执行的JS代码,且eval()
函数会受当前执行环境影响。var a = 100; eval('console.log(a)'); // 100
-
new Function
参考文献 Function | MDN
new Function
会将传入的字符串作为 函数,将传入的前几个参数作为 函数的参数。且 在Node环境中 他不会受外界的影响,因为new Function
与 最外级作用域是平级 的,在浏览器中不受影响。var a = 100; new Function('b','console.log(a)')(); // a is not defined
-
vm模块
参考文献 vm 虚拟机 | Node官网
vm
模块允许在 V8 虚拟机上下文中编译和运行代码。(关于
vm
模块的使用和原理,我会在后续文章中详细讲解)
本篇文章由莫小尚创作,文章中如有任何问题和纰漏,欢迎您的指正与交流。
您也可以关注我的 个人站点、博客园 和 掘金,我会在文章产出后同步上传到这些平台上。
最后感谢您的支持!