日常的学习笔记,包括 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

而模块中也有自己的分类,下面我们介绍一下 模块分类

  1. 核心模块 也叫内置模块,包括fshttppathvm 等等。在使用时 不需要进行安装,直接引入即可。引入的时候也 不需要添加绝对路径或相对路径
  2. 第三方模块 也就是别人定义的模块,像 co 等等。此类模块在使用的时候 需要进行安装
  3. 自定义模块 是用户自己封装或定义的模块,在使用的时候需要 通过绝对路径或者相对路径进行引入

常用的核心模块

fs模块

  1. fs.readFileSync

    我们先举个 核心模块 的例子。

    const fs = require('fs');
    // require内部使用的就是readFileSync来实现的
    let r = fs.readFileSync('./test.js','utf8');
    console.log(r);
    

    首先,require同步方法。假设require 是异步的话,那么每引入一个模块,我们都需要在其成功的回调中写我们下一步需要执行的代码,这样就会造成代码的冗余和堆积。

    所以 require 的内部就是使用 readFileSync 来实现的。

  2. fs.existsSync

    我们在读取文件时,如果读取的文件不存在,那么就会发生异常。

    let r = fs.readFileSync('./testxxx.js','utf8'); // 假设此文件不存在
    console.log(r); // 报错
    

    这时我们可以使用 existsSync 来对文件进行判断。

    let f = fs.existsSync('./testxxx.txt');
    console.log(f); // false
    

    此方法目前只有 同步方法,异步方法已经被废弃了

path模块

  1. 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', '/')); // 路径回到了根目录下
    

    (注:如果路径中存在 /,当前路径会回到跟目录下 )

  2. 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.joinpath.resolve 是可以互换使用的。但是在路径中出现 / 的情况下,还是使用 path.join更好。 **

  3. path.extname

    path.extname 会获取文件扩展名,也可以说就是文件的类型。

    const path = require('path');
    console.log(path.extname('text.min.js')); // .js
    
  4. path.basename

    path.basename 方法返回 path 的最后一部分。

    const path = require('path');
    console.log(path.basename('d:/xxx/xxx/xxx/test.js','.js'));  // test
    

    若不传最后一个参数,则会直接返回最后的文件名 test.js

  5. path.relative

    path.basename 方法会根据当前路径,获取相对路径

    const path = require('path');
    console.log(path.basename('a/b/c/test.js','a'));  // ..\..\..
    
  6. path.dirname

    path.dirname 方法会获取当前文件的父路径。

    const path = require('path');
    console.log(path.dirname('a/b/c'));  // a/b
    

    __dirname的实现就是用的path.dirname

vm模块

在说这个模块之前,我们可以先思考一个问题。

字符串如何能变成JS执行呢?

  1. eval函数

    参考文献 eval()函数

    我们第一个想到的就是 eval() 函数,他可以将传入的字符串或表达式转换成可以执行的JS代码,且 eval() 函数会受当前执行环境影响。

    var a = 100;
    eval('console.log(a)'); // 100
    
  2. new Function

    参考文献 Function | MDN

    new Function 会将传入的字符串作为 函数,将传入的前几个参数作为 函数的参数。且 在Node环境中 他不会受外界的影响,因为 new Function最外级作用域是平级 的,在浏览器中不受影响。

    var a = 100;
    new Function('b','console.log(a)')(); // a is not defined
    
  3. vm模块

    参考文献 vm 虚拟机 | Node官网

    vm 模块允许在 V8 虚拟机上下文中编译和运行代码。

    (关于vm模块的使用和原理,我会在后续文章中详细讲解)


本篇文章由莫小尚创作,文章中如有任何问题和纰漏,欢迎您的指正与交流。
您也可以关注我的 个人站点博客园掘金,我会在文章产出后同步上传到这些平台上。
最后感谢您的支持!

posted on 2021-11-16 21:00  莫小尚  阅读(141)  评论(0编辑  收藏  举报