os 模块

常用 API

API 描述
os.EOL 根据不同的操作系统生成对应的换行符
os.arch 系统架构
os.cpus cup 的相关信息
os.totalmem 总内存大小
os.freemem 空余内存大小(字节)
os.hostname 主机名
os.tmpdir 临时目录

基本用法

const os = require("os");

console.log(`你好,${os.EOL} 我叫大聪明`);
// 你好,
//  我叫大聪明

console.log(os.arch()); // x64

console.log(os.cpus().length); // 8

console.log(os.freemem() / 1024** 3); // 0.027233123779296875 GB

console.log(os.homedir()); // /Users/wushuai

console.log(os.hostname()); // ricepuddingMBP

console.log(os.tmpdir()); // /var/folders/_6/d__t939570jf2shy12ccp4gm0000gn/T

path 模块

常用 API

API 描述
path.basename 获取路径中的基础名称
path.dirname 获取路径中的目录名称
path.extname 获取路径中扩展名称
path.isAbsolute 判断路径是否为绝对路径
path.join 拼接多个路径
path.resolve 返回绝对路径
path.pasre 将路径解析成一个对象
path.formart 序列化路径

基本用法

  1. basename(path: string,ext?: string):获取路径中的基础名称;

    const path = require('path')
    console.log(__filename) // /Users/wushuai/Downloads/Code/02Path/01-path.js
      
    /**
     * 获取路径中的基础名称
      *  01 返回的就是接收路径当中的最后一部分 
      *  02 第二个参数表示扩展名,如果说没有设置则返回完整的文件名称带后缀
      *  03 第二个参数做为后缀时,如果没有在当前路径中被匹配到,那么就会忽略
      *  04 处理目录路径的时候如果说,结尾处有路径分割符,则也会被忽略掉
      */
    console.log(path.basename(__filename)) //  01-path.js
    console.log(path.basename(__filename, '.js')) //  01-path
    console.log(path.basename(__filename, '.css')) //  01-path.js
    console.log(path.basename('/a/b/c')) // c
    console.log(path.basename('/a/b/c/')) // c
    
  2. dirname(path: string):获取路径中的目录名称;

    const path = require('path')
    
    console.log(path.dirname('/a/b/c'))  //  /a/b
    console.log(path.dirname('/a/b/c/')) //  /a/b
    
  3. extname(path: string):获取路径中扩展名称;

    const path = require('path')
    /**
     * 获取路径的扩展名
      *  01 返回 path路径中相应文件的后缀名
      *  02 如果 path 路径当中存在多个点,它匹配的是最后一个点,到结尾的内容
      */
    console.log(path.extname('/a/b/index.js')) //  .js
    console.log(path.extname('/a/b')) // 
    console.log(path.extname('/a/b/index.html.js.css')) //  .css
    console.log(path.extname('/a/b/index.html.js.')) //  .
    
  4. isAbsolute(path: string):判断获取路径是否为绝对路径;

    const path = require('path')
    
    console.log(path.isAbsolute('foo')) // false
    console.log(path.isAbsolute('/foo')) // true
    console.log(path.isAbsolute('///foo')) // true
    console.log(path.isAbsolute('')) // false
    console.log(path.isAbsolute('.')) // false
    console.log(path.isAbsolute('../bar')) // false
    
  5. join(…path: string[]):拼接多个路径判断;

    const path = require('path')
    
    console.log(path.join('a/b', 'c', 'index.html')) // a/b/c/index.html
    console.log(path.join('/a/b', 'c', 'index.html')) // /a/b/c/index.html
    console.log(path.join('/a/b', 'c', '../', 'index.html')) // /a/b/index.html
    console.log(path.join('/a/b', 'c', './', 'index.html')) // /a/b/c/index.html
    console.log(path.join('/a/b', 'c', '', 'index.html')) // /a/b/c/index.html
    console.log(path.join('')) // .
    
  6. resolve(…from?: string[], to: string):返回绝对路径;

    const path = require('path');
                
    // to 不是一个绝对路径,form优先被考虑,直到找到一个绝对路径
    console.log(path.resolve('/foo/bar', '../', './baz')); // 返回 /foo/bar
    // to 是一个绝对路径,那么久直接返回 to
    console.log(path.resolve('/foo/bar','/baz')); // 返回 /baz
    // 如果 from 和 to 都不是绝对路径的话,就会使用当前的工作目录 + form + to
    console.log(path.resolve('foo', 'bar')); 
    // /Users/wushuai/Downloads/Code/02Path/foo/bar
    
  7. pasre(path: string):将路径解析成一个对象;

    const path = require('path')
    
    console.log(path.parse('/a/b/c/index.html'))
    // { root:'/',dir:'/a/b/c',base:'index.html',ext:'.html', name: 'index' }
    console.log(path.parse('/a/b/c/'))
    // { root: '/', dir: '/a/b', base: 'c', ext: '', name: 'c' }
    console.log(path.parse('./a/b/c/'))
    // { root: '', dir: './a/b', base: 'c', ext: '', name: 'c' }
    
  8. formart(pathObj: Object):序列化路径;

    const path = require('path');
    
    // 如果提供了 pathObject.dir,则 pathObject.root 会被忽略。
    const str = {
        root: '/ignored',
        dir: '/node/base/path',
        base: 'index.js',
        ext: '.js',
        name: 'index'
    };
    console.log(path.format(str)); // 输出 /node/base/path/index.js
    
    // 如果没有提供了 pathObject.dir,则 pathObject.root 会使用。
    const str2 = {
        root: '/',
        base: 'index.js',
        ext: '.js',
        name: 'index'
    };
    console.log(path.format(str2)); // 输出 /index.js
    
    // 如果没有指定 'base', 则 'name' + 'ext' 会被使用
    const str3 = {
        root: '/',
        ext: '.js',
        name: 'index'
    };
    console.log(path.format(str3)); // 输出 /index.js
    
  9. normalize(path: string):规范化路径;

    const path = require('path')
    
    console.log(path.normalize('')) // .
    console.log(path.normalize('a/b/c/d')) // a/b/c/d
    console.log(path.normalize('a///b/c../d')) // a/b/c../d
    console.log(path.normalize('a///b/c\/d')) // a/b/c/d
    console.log(path.normalize('a//\b/c\/d')) // \b为转译字符,被去掉了,a/c/d
    

util 模块

常用 API

API 描述
util.callbackify 将返回 Promise 的函数转换为接受回调的函数
util.promisify 将一个基于回调的异步函数转换为返回 Promise 的函数
util.isDeepStrictEqual 用于检查两个值是否深度严格相等

基本用法

JS
JS
JS
const util = require("util");

async function delay(duration = 1000) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(duration);
    }, duration);
  });
}
const delayCallback = util.callbackify(delay);

delayCallback(500, (err, d) => {
  console.log(d);
});
const util = require("util");
function delayCallBack(duration, callback) {
  setTimeout(() => {
    callback(null, duration);
  }, duration);
}

const delay = util.promisify(delayCallBack);
(async () => {
  const r = await delay(500);
  console.log(r);
})();
const util = require("util");

const obj1 = {
  a: 1,
  b: {
    c: 3,
    d: {
      e: 5
    }
  }
};
const obj2 = {
  a: 1,
  b: {
    c: 3,
    d: {
      e: 5,
      g: 6
    }
  }
};
console.log(util.isDeepStrictEqual(obj1, obj2));

vm 模块

  1. Nodejs 底层的 require 实现用到了这个模块

  2. 它的核心作用是可以创建一个独立运行代码的沙箱环境,所谓 “沙箱” 可以理解为 “独立”、“封闭”;

  3. 此处不讨论 vm 模块 API 的使用语法和细节,主要了解如何运用 vm 模块为实现模块的加载做准备,也就是怎么通过 vmA 模块中的内容,放在 B 模块中执行;

三种模块化方案对比

eval

使用 eval 运行 JS 代码(没有独立的作用域)

TXT
JS
// test.txt 开始
var age = 18
// test.txt 结束
const fs = require('fs')
let content = fs.readFileSync('test.txt', 'utf-8')

eval(content)
// let age = 20
// content 和当前作用域下已经有了相同名称的 age 变量,这个脚本就会报错:
// SyntaxError: Identifier 'age' has already been declared
// Nodejs 中加载的每个模块都拥有独立的作用域,所以 eval 显然不适合

new Function

new Function 虽然能创建独立作用域,不过需要手动指定作用域内需要的外部变量,当需要传入的变量增多,处理起来就相对麻烦了;一般用于模板引擎;

TXT
JS
// test.txt 开始
var age = 18
// test.txt 结束
let age = 20

// new Function
// 最后一个参数是函数体内容的字符串
// 前面的参数是函数接收的形参名称,可以分别传入,也可以用逗号拼接在一起
const fn = new Function('age', 'return age + 1')
console.log(fn(age)) // 21

vm 模块(推荐)

  1. vm.runInThisContext(code) 创建的沙箱环境保证代码不会与加载模块的外部作用域中的变量发生冲突;

  2. 既解决了可以执行外部读取到的其它模块的内容,同时还把模块中的作用域与外部作用域进行了隔离,避免同名变量冲突;

  1. vm.runInThisContext(code) 会在当前全局变量的上下文,为运行的代码创建一个与当前作用域隔离的沙箱环境,环境中只能访问全局变量,无法访问当前作用域中的变量;

    TXT
    JS
    // test.txt 开始
    var age = 18
    // test.txt 结束
    
    const fs = require('fs')
    const vm = require('vm')
    
    let content = fs.readFileSync('test.txt', 'utf-8')
    let age = 20
    
    vm.runInThisContext(content)
    console.log(age) // 20
    
  2. 沙箱环境在当前全局变量的上下文,可以访问全局变量 gloabl ,全局上下文中 var 声明的变量会添加到全局变量 global 中;

    TXT
    JS
    // test.txt 开始
    var age = 18
    // test.txt 结束
    
    const fs = require('fs')
    const vm = require('vm')
    
    let content = fs.readFileSync('test.txt', 'utf-8')
    let age = 20
    
    vm.runInThisContext(content)
    console.log(age) // 20
    console.log(global.age) // 18
    
  3. let 声明的变量就不会添加到全局对象,Nodejsmoduleexportsrequire 等都是使用 let 声明的;

    TXT
    JS
    // test.txt 开始
    let age = 18
    // test.txt 结束
    
    const fs = require('fs')
    const vm = require('vm')
    
    let content = fs.readFileSync('test.txt', 'utf-8')
    let age = 20
    
    vm.runInThisContext(content)
    console.log(age) // 20
    console.log(global.age) // undefined
    

手写 ejs 模板引擎

  1. with(obj):执行 with 函数,obj 为执行上下文;

  2. new Function():将字符串执行;

  3. 字符串拼接;

  4. 正则表达式;

整理流程

  1. 读取模板 index.html

  2. 将模板转成 js 字符串,并利用正则将模板中的 <%= %><% %> 全部去掉;

  3. 利用 new Function 形成一个沙箱环境,让 with 在沙箱中执行字符串代码;

模板 index.html 代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <%arr.forEach((item)=>{%>
        
  • <%=item%>
  • <%})%> < body> html> < code>

    利用 with、new Function、正则,将模板 html 转成下面的字符串并执行

    'let str = ""
    with (obj) {
        str += `<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
        `
        arr.forEach((item) => {
            str += `<li>${item}></li>`
        })
        str += `
    </body>
    </html>`
        return str
    }'
    

    实现代码

    let fs = require('fs');
    let path = require('path');
    let str = fs.readFileSync(path.resolve(__dirname, 'index.html'), 'utf8');
    
    function render(str, obj) {
        let head = 'let str = ""\r\nwith(obj){\r\n';
        head += 'str+= `'
        let tail = '`\r\n return str}'
    
        // + 原子符号
        // ? 号的作用 
        // () 分组
        // 把 <%= %> 全部去掉
        str = str.replace(/<%=(.+?)%>/g, ($0, $1) => '${' + $1 + '}')
        // 把 <% %> 全部去掉
        let content = str.replace(/<%(.+?)%>/g, ($0, $1) => '`\r\n' + $1 + '\r\nstr+=`');
        
        let fn = new Function('obj', head + content + tail);
        return fn(obj); // 或者这样写 return fn.call(null, obj);
    }
    let newStr = render(str, { arr: [1, 2, 3] });
    console.log(newStr);
    

    模板转成 html 展示

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
        <li>1</li>
    
        <li>2</li>
    
        <li>3</li>
    </body>
    </html>
    
    打赏作者
    您的打赏是我前进的动力
    微信
    支付宝
    评论

    中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

    粽子

    这有关于前端开发的技术文档和你分享。

    相信你可以在这里找到对你有用的知识和教程。

    了解更多

    目录

    1. 1. os 模块
      1. 1.1. 常用 API
      2. 1.2. 基本用法
    2. 2. path 模块
      1. 2.1. 常用 API
      2. 2.2. 基本用法
    3. 3. util 模块
      1. 3.1. 常用 API
      2. 3.2. 基本用法
    4. 4. vm 模块
      1. 4.1. 三种模块化方案对比
        1. 4.1.1. eval
        2. 4.1.2. new Function
        3. 4.1.3. vm 模块(推荐)
      2. 4.2. 手写 ejs 模板引擎
        1. 4.2.1. 整理流程
        2. 4.2.2. 模板 index.html 代码
        3. 4.2.3. 利用 with、new Function、正则,将模板 html 转成下面的字符串并执行
        4. 4.2.4. 实现代码
        5. 4.2.5. 模板转成 html 展示