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