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 | 序列化路径 |
基本用法
-
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
-
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
-
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.')) // .
-
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
-
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('')) // .
-
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
-
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' }
-
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
-
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 | 用于检查两个值是否深度严格相等 |
基本用法
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 模块
Nodejs 底层的 require 实现用到了这个模块
它的核心作用是可以创建一个独立运行代码的沙箱环境,所谓 “沙箱” 可以理解为 “独立”、“封闭”;
此处不讨论 vm 模块 API 的使用语法和细节,主要了解如何运用 vm 模块为实现模块的加载做准备,也就是怎么通过 vm 把 A 模块中的内容,放在 B 模块中执行;
三种模块化方案对比
eval
使用 eval 运行 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 虽然能创建独立作用域,不过需要手动指定作用域内需要的外部变量,当需要传入的变量增多,处理起来就相对麻烦了;一般用于模板引擎;
// 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 模块(推荐)
vm.runInThisContext(code) 创建的沙箱环境保证代码不会与加载模块的外部作用域中的变量发生冲突;
既解决了可以执行外部读取到的其它模块的内容,同时还把模块中的作用域与外部作用域进行了隔离,避免同名变量冲突;
-
vm.runInThisContext(code) 会在当前全局变量的上下文,为运行的代码创建一个与当前作用域隔离的沙箱环境,环境中只能访问全局变量,无法访问当前作用域中的变量;
TXTJS// 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
-
沙箱环境在当前全局变量的上下文,可以访问全局变量 gloabl ,全局上下文中 var 声明的变量会添加到全局变量 global 中;
TXTJS// 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
-
let 声明的变量就不会添加到全局对象,Nodejs 中 module、exports、require 等都是使用 let 声明的;
TXTJS// 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 模板引擎
with(obj):执行 with 函数,obj 为执行上下文;
new Function():将字符串执行;
字符串拼接;
正则表达式;
整理流程
-
读取模板 index.html;
-
将模板转成 js 字符串,并利用正则将模板中的 <%= %>、<% %> 全部去掉;
-
利用 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>
webpack🤚 webpack5 模块联邦
上一篇