模块
模块
- 允许代码分离,将其组织为可维护的单元,提升代码的可复用性和可读性;
- CommonJS(CJS)、ECMAScript Modules(ESM)
CJS模块系统
- 导出模块 只需要使用module.exports或exports将模块中的内容导出即可
- module.exports,
// 指定属性导出
module.exports.byebye = function (name) {
console.log(`byebye, ${name}!`)
}
module.exports.userInfo = {
name: 'dd',
age: 18
}
// 统一的对象导出
// 在模块中定义一个byebye函数
function byebye(name) {
console.log(`byebye, ${name}!`)
}
// 定义了一个名为 userInfo 的对象,包含姓名和年龄两个属性
const userInfo = {
name: 'dd',
age: 18
}
// 将函数和对象统一导出到模块的外部
module.exports = {
byebye,
userInfo
}
- exports
// 定义一个模块,使用 exports 导出模块中的内容。
// 定义了一个名为 byebye 的函数,用于输出告别语
// 定义了一个名为 userInfo 的对象,包含姓名和年龄两个属性
exports.byebye = function (name) {
console.log(`byebye, ${name}!`)
}
exports.userInfo = {
name: 'dd',
age: 18
}
- module.exports vs exports
module.exports 和 exports 都可用于导出 Node.js 模块中的代码的对象;
exports实际上是module.exports的一个引用,当使用exports导出模块代码时,实际上是在向module.exports添加属性
// 导出一个名为 "hello" 的函数到 "exports" 对象中
// 函数中会将 "Hello World!" 的信息输出到控制台中
exports.hello = function() {
console.log("Hello World!");
};
// 导出一个名为 "hello" 的函数到 "exports" 对象中
// 函数中会将 "Hello World!" 的信息输出到控制台中
module.exports.hello = function() {
console.log("Hello World!");
};
// 建议在写 Node.js 模块时,只使用 module.exports 导出模块代码,而不要使用 exports。如果你需要向外部导出多个函数或对象,可以将它们作为 module.exports 的属性导出;
// 外部就可以通过 require 方法导入该模块,并访问其中的 hello 和 bye 方法了。
module.exports = {
hello: function() {
console.log("Hello World!");
},
bye: function() {
console.log("Goodbye World!");
}
};
- 引入模块
(1)完整引入
// 导入模块 "./exports" 并将其赋值给变量 context
const context = require('./exports')
// 调用 context 模块中的 hello 函数,并传入 context.userInfo.name 参数
context.hello(context.userInfo.name)
(2)解构引入
// 当导出内容是一个对象时,可以使用解构引入。
// 导入模块 "./exports" 中的 hello, userInfo 和 byebye,并赋值给相应的变量
const { hello, userInfo, byebye } = require('./exports')
// 调用 hello 函数,并传入 userInfo.name 参数
hello(userInfo.name)
ES Modules模块系统(ESM)
- import/export
- 默认情况下,.js文件识别为CJS模块;如果需要识别为ES模块,有2种方式:1. 使用.mjs命名;2. package.json种的type字段设置为module;
// package.json
{
"type":"module"
}
- 默认导入导出,使用export default (export default,import xx from 'module');
// 文件 export_default.js
// 导出默认对象
export default {
// 定义 byebye 方法,输出道别信息
byebye(name) {
console.log(`byebye, ${name}!`)
},
// 定义 userInfo 对象,存储用户信息
userInfo: {
name: 'dd', // 用户名
age: 18 // 用户年龄
}
}
// 文件 import_default.js
// 引入 export_default.js 中默认导出的模块
import defaultModule from './export_default.js'
// 调用 defaultModule 中定义的 byebye() 方法,输出道别信息并传入用户姓名
defaultModule.byebye(defaultModule.userInfo.name)
- 具名导入导出,使用export (export xx,import { xx } from 'module');
// 文件 export.js
// 定义 byebye 方法,输出道别信息
export function byebye(name) {
console.log(`byebye, ${name}!`)
}
// 定义 userInfo 对象,存储用户信息
export const userInfo = {
name: 'dd', // 用户名
age: 18 // 用户年龄
}
// 文件 import.js
// 引入 export_named.js 中具名导出的模块,使用 as 关键字还可以修改导入内容的名称
import { byebye, hello, userInfo as user } from './export_named.js'
// 调用 byebye() 方法,输出道别信息并传入用户姓名
byebye(user.name)
- 导入导出所有对象,可以将另一个模块的内容直接全部导出,导出同时也可以设置默认导出; (export *,import * as xx from 'module');
// 文件 export_all.js
// 从 export.js 中导出所有的模块成员
export * from './export.js'
// 导出一个默认模块,对象包含 goal 属性,初始值为 'learn'
export default {
goal: 'learn'
}
// 文件 import_all.js
// 导入 export_all.js 中所有被导出的模块成员,并作为 allValues 对象的属性
import * as allValues from './export_all.js'
// 在控制台输出 allValues 对象
console.log(allValues)
// 从 allValues 对象中解构出 hello、byebye、default 和 userInfo 模块成员
const { byebye, default: data, userInfo } = allValues
// 调用 byebye() 方法,输出道别信息并传入用户姓名
byebye(userInfo.name)
// 输出 data 对象的 goal 属性
console.log(data.goal)
- 重新导出 (export { xx } from 'module',export * from 'module')
// lib.js
export function hello(name) {
console.log(`Hello, ${name}!`)
}
export default {
filename: 'lib.js',
des: 'lib.js的一些默认导出'
}
// util.js
export function byebye(name) {
console.log(`ByeBye, ${name}!`)
}
export default {
filename: 'util.js',
des: 'util.js的一些默认导出'
}
// index.js
// 从 './lib.js' 中导出 hello 和默认导出并重命名为 libData
export { hello, default as libData } from './lib.js'
// 从 './util.js' 中导出所有命名导出
export * from './util.js'
// 从 './util.js' 中默认导出并重命名为 utilData
export { default as utilData } from './util.js'
// 使用的时候,就统一通过 index.js 引入即可。
// usage.js
import { hello, byebye, libData, utilData } from './index.js'
hello(libData.filename)
byebye(utilData.filename)
CJS vs ESM
-
模块加载时机
CJS支持动态加载模块,require语句可以出现在任意位置;CJS 需要等到代码运行时才能确定依赖关系和加载模块;
ESM会在所有模块都加载完毕后才执行代码,在使用导入的内容之前导入;ESM 可以在代码执行前进行静态分析和优化,从而提高性能; -
导出内容的区别
ESM 中,当我们导入一个变量时,实际上是导入了该变量的引用。这意味着,如果导出的变量在导入模块中发生了改变,导入的变量也会随之改变。
CommonJS 中,导入的是导出模块的值的拷贝,而不是引用。这意味着,即使导出模块中的值发生了改变,导入模块中导入的变量不会受到影响。
ESM 导入的是值的引用,而 CJS 导入的是值的拷贝。
- 文件命名
模块一般都以 .js 结尾,通过 package.json 中 "type":"module" 区分模块类型;
还可通过文件命名来区分 .cjs 表明是 CJS 规范的模块,.mjs 表明是 ESM 规范的模块。
常用的内置模块
- global 全局对象,挂载了一些常用方法和属性
- path 提供与文件路径相关的实用工具方法
- fs 文件系统模块,用于操作文件和目录
- util 提供一些实用工具函数
- http 用于创建 HTTP 服务器,也可用于向已有服务发起请求并获取响应
- child_process 用于创建操作子进程
全局变量
- js中存在一个特殊的全局对象,可以在任意位置被房屋,通常用globalThis指代。 浏览器中,指向window,node.js中指向global。
- 直接使用一些无需定义的方法时,都是global上的属性,如console,setTimeout。
- 特殊全局变量:__filename,表示当前正在执行的脚本文件的绝对路径;__dirname ,表示当前执行脚本所在目录的绝对路径;(这两个变量只在CJS下存在)
- 常用global属性:process(提供了与当前 Node.js 进程相关的信息和控制方法),Buffer( 用于处理二进制数据)
// process.argv 返回一个数组,包含启动 Node.js 进程时传递的命令行参数。
// process.cwd() 获取当前工作目录的绝对路径。
// process.version 获取当前 Node 版本。
// process.env 获取当前执行环境的环境变量 (对象形式)。
// process.pid:返回进程的 PID (进程 ID);
// process.platform:返回运行 Node.js 的操作系统平台;
// process.arch:获取 CPU 架构信息
// process.stdout:标准输出流,常用 process.stdout.write 进行数据写入。
process.stdout.write('hello')
// process.stdin:用于从标准输入流 (stdin) 读取数据。
// 监听用户输入数据
process.stdin.on('data', (data) => {
console.log(`User input: ${data}`);
});
// 创建Buffer对象
const buf = Buffer.alloc(10); // 创建一个大小为 10 的 Buffer 对象,默认会用 0 填充
const buf2 = Buffer.from('Hello, world!'); // 创建一个包含字符串 'Hello, world!' 的 Buffer 对象
const buf3 = Buffer.from([0x68, 0x65, 0x6c, 0x6c, 0x6f]); // 内容为hello构成的16进制数组 Buffer 对象
// 转换内容格式
const buf = Buffer.from('Hello, world!');
// 转为字符串输出
console.log(buf.toString()); // 输出 'Hello, world!'
// 转为16进制字符串输出
console.log(buf.toString('hex')); // 输出 '48656c6c6f2c20776f726c6421'(对应的是 'Hello, world!' 的 ASCII 码)
// 转为数组输出
console.log(Array.from(buf));
// 转为base64格式输出
console.log(buf.toString('base64')); // 输出 'SGVsbG8sIHdvcmxkIQ=='
// 写入内容
// 创建一个长度为 10 的 Buffer 实例并将它填充为 0
const buf = Buffer.alloc(10);
// 将字符串 'Hello' 写入 Buffer 实例的前 5 个字节
buf.write('Hello');
// 将字符串 'world' 写入 Buffer 实例的第 6 个字节开始的位置,由于 'world' 的长度为 5,所以不会覆盖掉之前写入的 'Hello'
buf.write('world', 5);
// 将 Buffer 实例转换为字符串并输出 'Hello world'
console.log(buf.toString());
// 合并多个Buffer对象
const buf1 = Buffer.from('Hello');
const buf2 = Buffer.from('World');
const buf3 = Buffer.concat([buf1, buf2]);
console.log(buf3.toString()); // 输出 'HelloWorld'
// 截取Buffer对象
const buf = Buffer.from('Hello, world!');
const buf2 = buf.slice(0, 5);
console.log(buf2.toString()); // 输出 'Hello'
path路径处理
// path.join 将多个路径拼接成一个相对路径 (或绝对路径,取决于第一个路径是否为根路径)。
import path from 'path'
console.log(path.join('a', 'b', 'c'))
console.log(path.join(process.cwd(), '/hello', 'world'))
// path.resolve 将多个路径拼接成一个绝对路径,返回一个解析后的绝对路径。即如果传入相对路径,会以当前工作目录为基准,计算出绝对路径,如果传入了绝对路径,则以传入的绝对路径为基准。
import path from 'path';
console.log('=== path.resolve ===')
console.log(path.resolve('a', 'b', 'c'))
console.log(path.resolve('/hello', 'world', './a', 'b'))
// path.dirname 返回路径中的目录名
console.log('=== path.dirname ===')
console.log(path.dirname(process.cwd()))
console.log(path.dirname('/a/b/c'))
// path.basename 返回路径中的文件名,并可选地去除给定的文件扩展名。
console.log('=== path.basename ===')
console.log(path.basename('a/b/c.js'))
console.log(path.basename('a/b/c.js', '.js'))
console.log(path.basename('a/b/c.js', 'js'))
console.log(path.basename('a/b/c.js', 's'))
// path.extname 获取路径中的文件扩展名。
console.log('=== path.extname ===')
console.log(path.extname('a/b/c.js'))
console.log(path.extname('a/b/c'))
console.log(path.extname('a/b/c.d.ts'))
console.log(path.extname('a/b/.npmrc'))
// path.normalize 主要用于规范化路径,将路径中的不规范部分调整为标准格式
console.log('=== path.normalize ===')
console.log(path.normalize('a//b//c/d/e/..'))
// path.parse 用于解析文件路径,将其拆分为一个对象。
console.log('=== path.parse ===')
console.log(path.parse('/home/user/dir/file.txt'))
// path.sep 返回当前系统文件路径使用的分隔符。避免因为不同操作系统使用不同的文件路径分隔符而导致的错误。更推荐使用 path.join 方法来拼接文件路径:
console.log('=== path.sep ===')
console.log('foo/bar/baz'.split(path.sep))
const dir = 'users'
const file = 'index.html'
console.log(dir + path.sep + file)
fs文件系统
- 用于操作文件和目录;支持同步 (sync) 或者异步 (async/callback) 调用,其中同步调用会阻塞主线程,异步调用不会阻塞。
import fs from "fs";
// 同步读取
const syncData = fs.readFileSync('./test.txt', 'utf-8');
console.log('syncData: ', syncData);
// 回调形式,异步读取
fs.readFile('./test.txt', 'utf-8', (err, callbackData) => {
if (!err) {
console.log('callbackData: ', callbackData);
}
})
// promise形式 异步读取
fs.promises.readFile('./test.txt', 'utf-8').then((promiseData) => {
console.log('promiseData: ', promiseData);
})
- 文件操作
// 读取文件
import fs from 'fs'
const txtContent = fs.readFileSync('./test.txt', 'utf-8')
// 以二进制形式读取,操作。
const buf = fs.readFileSync('./test.txt')
// 打印Buffer大小
console.log(buf.length)
// 修改前2个字符
buf.write('gg')
// 输出修改后的内容
console.log(buf.toString())
// 写入文件
fs.writeFileSync('./newTest.txt', 'hello world')
// 写入二进制文件
// 读取一个图片
const imgBuf = fs.readFileSync('./logo.png')
console.log('isBuffer', Buffer.isBuffer(imgBuf), 'bufferSize', imgBuf.length)
// 写入到新文件
fs.writeFileSync('newLogo.png', imgBuf, 'binary')
// 获取文件或目录的基本信息
import fs from 'fs'
console.log(fs.statSync('./test.txt'))
console.log(fs.statSync('./test-dir'))
// 返回的对象上还包含可直接调用的方案,用于判断文件类型。
const fileInfo = fs.statSync('./test.txt')
// 判断是文件还是目录
console.log(fileInfo.isFile(), fileInfo.isDirectory())
const dirInfo = fs.statSync('./test-dir')
// 判断是文件还是目录
console.log(dirInfo.isFile(), dirInfo.isDirectory())
try {
// 查询一个不存在的文件/目录信息(会抛出异常,需要自行捕获)
fs.statSync('not_exist.txt')
} catch (e) {
console.log('文件不存在')
}
// 追加输出,fs.appendFileSync向文件末尾追加写入内容
import fs from "fs";
fs.appendFileSync("test.txt", "hello");
// 移动或重命名文件 fs.renameSync
import fs from "fs";
fs.renameSync('test.txt', 'test2.txt');
fs.renameSync("test2.txt", "test-dir/test2.txt");
// 删除文件 fs.unlinkSync fs.rmSync都可用于单文件删除,fs.rmSync还支持删除目录,递归删除子文件或目录
fs.rmSync('test-dir', {recursive: true});
- 目录操作
// 读取目录所有文件fs.readdirSync
import fs from "fs";
const files = fs.readdirSync('test-dir');
const files2 = fs.readdirSync('test-dir', {withFileTypes: true});
console.log(files, files2);
// 创建目录fs.mkdirSync recursive:true递归创建
fs.mkdirSync('test-dir/a/b/c', {recursive: true});
// 删除目录 fs.rmdirSync recursive:true表明删除包含其子目录
fs.rmdirSync('test-dir/a', {recursive: true});
fs.rmSync('test-dir/a', { recursive: true })
// 监听目录变更fs.watch
// 监听当前目录下所有的文件和子目录中的文件
fs.watch('./', {recursive: true}, (eventType, filename) => {
console.log(`File '${filename}' has changed: ${eventType}`)
})
util工具
// 对象转字符串:util.inspect(object, [options]),常与 console.log 搭配使用,可以友好的将对象转为字符串,打印更加友好。
// 复杂对象
const testObj = {
a: 1,
b: {
c: 2,
d: [3, 4, 5],
e: () => {
console.log(6)
}
},
f: '7',
g: [{ 8: [{ 9: 10 }] }],
h() {
console.log(11)
}
}
console.log(testObj); // 普通打印,可以看到嵌套的数组和函数没有办法打印出来
console.log(JSON.stringify(testObj, null, 2)); // 函数没有了
console.log(util.inspect(testObj, { depth: Math.Infinity })); // 深层的数组和对象被展开了,嵌套函数看不到
// npm i javascript-stringify
import { stringify } from 'javascript-stringify'
console.log(stringify(testObj, null, 2)); // 能保持和传入的结果基本一致。
// 格式化字符串 util.format
import util from 'util'
console.log(util.format('%s:%s', 'foo', 'bar')) // 'foo:bar'
console.log(util.format('%d + %d = %d', 1, 2, 3)) // '1 + 2 = 3'
console.log(
util.format('My name is %j', { firstName: 'John', lastName: 'Doe' })
)
// 判断数据类型
import util from 'util'
// 判断数据类型
console.log(util.isArray([])) // true
console.log(util.isRegExp(/some regexp/)) // true
console.log(util.isDate(new Date())) // true
console.log(util.isPrimitive(null)) // true
console.log(util.isPrimitive(1)) // true
// 回调转promise util.promisify(original) 用于将常规带有回调函数的方法转为返回Promise对象的方法
import util from "util";
import fs from "fs";
// 将fs.readFile方法转为返回Promise的函数
const fsRead = util.promisify(fs.readFile);
// 使用Promise的方式读取文件内容并输出
fsRead('./package.json').then((data) => {
console.log(data.toString());
})
--
http/https
- 用于创建HTTP服务器,也可用于向已有的服务发起请求并获取响应
// http.get 发起请求
import https from "https";
https.get('https://api-url',
(res) => {
// 响应内容
let content = "";
res.on('data', (chunk) => {
content += chunk;
});
// 读完对我暴露内容和状态码
res.on('end', () => {
console.log(content);
});
res.on('error', (er) => {
console.log(err);
})
}
)
// 传参
const req = https.get(
'https://api-url',
{
headers: {
'Content-Type': 'application/json'
}
}
)
req.on('response', (res) => {
// 响应内容拼接
let content = ''
res.on('data', (chunk) => {
content += chunk
})
res.on('end', () => {
console.log(content)
})
res.on('error', (err) => {
console.log(err)
})
})
// http.request
import https from 'https'
const url = new URL(
'https://api-url'
)
const req = https.request(
{
// 设置请求方法
method: 'GET',
// http 80 https 443
port: 443,
hostname: url.hostname,
path: url.pathname + url.search
},
(res) => {
let content = ''
res.on('data', (chunk) => {
content += chunk
})
res.on('end', () => {
console.log('statusCode', res.statusCode)
console.log(content)
})
}
)
// 发送请求
req.end()
// fetch
fetch(
'https://api-url'
)
.then((res) => res.json())
.then((data) => {
console.log(data)
})
.catch((err) => {
console.error(err)
})
// axios
// npm i axios
axios
.get(
'https://api-url'
)
.then((res) => {
console.log(res.data)
})
.catch((err) => {
console.error(err)
})
// server.mjs http.createServer创建Web服务
import http from 'http'
const server = http.createServer((req, res) => {
// 获取请求的路径和方法
const { url, method } = req
res.statusCode = 200
res.setHeader('Content-Type', 'text/html')
res.end('<h1>Hello, World!</h1>')
})
server.listen(4275, () => {
console.log('Server running at http://127.0.0.1:4275/')
})
// node server.mjs
// 启动后可以通过fetch调用
fetch('http://127.0.0.1:4275?hello=world', {
method: 'POST'
})
// request内容
// query 参数解析
// /a/b/c?name=123&age18
fetch('http://127.0.0.1:4275?hello=world', {
method: 'POST'
})
const { url, method } = req
const query = Object.fromEntries(
new URL(url, 'http://localhost').searchParams
)
// body 参数解析
fetch('http://127.0.0.1:4275?hello=world', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'xm',
age: 18
})
})
// 通过监听data和end事件获取
let body = []
req
.on('data', (chunk) => {
body.push(chunk)
})
.on('end', () => {
body = Buffer.concat(body).toString()
body = JSON.parse(body)
console.log('body', body)
})
// headers 参数解析
console.log('headers', req.headers)
// response内容
// 设置响应状态码为 200
res.statusCode = 200;
// 设置响应头,指定响应内容类型为 text/html
res.setHeader('Content-Type', 'text/html');
// 发送响应内容到客户端,结束响应
res.end('<h1>Hello, World!</h1>');
res.setHeader('Content-Type', 'application/json')
chiild_process 用于创建子进程
- js单线程,但通过创建子进程也能实现多任务并行处理,也可以通过其调用系统的功能指令完成复杂的任务
- 提供了4个方法:spawn、exec、execFile、fork
pwd 获取当前目录的路径,ls 获取当前目录下的文件
// spawn异步 spawnSync同步 启动一个子进程来执行指定的命令,并且可以通过流式数据通信与子进程进行交互
import ChildProcess from 'child_process'
const { spawn, spawnSync } = ChildProcess
const pwd = spawnSync('pwd')
console.log(pwd.stdout.toString())
const ls = spawnSync('ls', ['-lh'])
console.log(ls.stdout.toString())
// exec,execSync 启动一个 shell,并在 shell 中执行指定命令,执行完毕后插入 stdout/stderr 中,适用于一些命令行工具;
import { exec, execSync } from 'child_process'
const pwd = execSync('pwd')
console.log(pwd.toString())
const ls = execSync('ls -lh')
console.log(ls.toString())
const file = './../fs/index.mjs'
const execProcess = exec(`git log -1 --pretty="%ci" ${file}`)
execProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data}`)
console.log(new Date(data))
})
// execFile 方法 执行某个可执行文件,支持同步和异步两种方式, 可以直接执行某个文件,而无需通过 shell 执行
// hello.js
#!/usr/bin/env node
const hello = 'hello world'
console.log(hello)
console.log(process.env)
// test.js
import { execFile, execFileSync } from 'child_process'
const file = './hello'
const execData = execFileSync(file)
console.log(execData.toString())
execFile(file, (error, stdout, stderr) => {
if (error) {
throw error
}
console.log(stdout)
console.log(stderr)
})
// fork() 方法创建一个子进程,并与子进程进行通信 专门用于在 Node.js 中衍生新的进程来执行 JavaScript 文件,并且建立一个与子进程的 IPC 通信管道。
// child.mjs
process.on('message', (msg) => {
// 监听来自父进程的消息
console.log(`Message from parent: ${msg}`)
process.send('Hello from child!') // 向父进程发送消息
})
// form.mjs
import { fork } from 'child_process'
const child = fork('child.mjs') // 使用 fork() 方法创建子进程
child.on('message', (msg) => {
// 监听来自子进程的消息
console.log(`Message from child: ${msg}`)
})
child.send('Hello from parent!') // 向子进程发送消息
url模块
// url.parse 解析 URL 字符串,返回一个解析后的对象。
import url from 'url'
const testUrl = 'https://www.baidu.com?search=juejin'
console.log(url.parse(testUrl))
// url.URL 和全局的 URL 一样,创建一个 URL 实例,提供许多开箱即用的操作。
import url from 'url'
const testUrl = 'https://www.baidu.com?search=juejin'
console.log('url.URL === URL', url.URL === URL)
console.log(new URL(testUrl))
Timers
- 定时器相关方法
setImmediate(() => console.log('setImmediate'))
setTimeout(() => console.log('setTimeout'), 0)
process.nextTick(() => console.log('nextTick'))
setInterval(() => console.log('setInterval'), 1000)
Readline模块
- readline 模块提供了一个接口,用于从可读流 (例如 process.stdin) 读取数据,并支持逐行读取数据。
// 使用 question() 方法向用户询问姓名并显示
import readline from "readline";
const rl = readline.createInterface({
input: process.stdin,
outut: process.stdout,
});
rl.question('what is your name?', (name) => {
console.log(`hello, ${name}`);
rl.close();
})
// 使用 write() 方法向标准输出发送数据。
import readline from "readline";
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.write('hello');
rl.close();
// prompt 实现一个可多轮对话的命令行
const rl = readline.createInterface({
input: process.stdin, // 从标准输入流中读取数据
output: process.stdout // 输出数据到标准输出流中
})
rl.setPrompt('node> ') // 设置提示符
rl.prompt() // 显示提示符
rl.on('line', (line) => {
// 监听行事件
switch (
line.trim() // 去除收尾空白字符,进行简单的命令选择判断
) {
case 'hello':
console.log('world') // 输出 'world'
break
case 'exit':
rl.close() // 关闭 readline 接口
break
default:
console.log(`Say what? I might have heard '${line.trim()}'`) // 输出收到的指令
break
}
rl.prompt() // 显示提示符
})
rl.on('close', () => {
// 监听关闭事件
console.log('Goodbye!') // 输出 'Goodbye!'
process.exit(0) // 退出 Node.js 进程
})
crypto模块
- 主要用于加密和解密数据,内置了一些常用的算法, 哈希值生成,加解密,随机数生成。
// 生成具有给定大小的随机数据 (Buffer 类型)。
console.log(crypto.randomBytes(32).toString('hex'))
console.log(crypto.randomBytes(8).toString('hex'))
参考&感谢各路大神
node
宝剑锋从磨砺出,梅花香自苦寒来。