import{_ as s,o as n,c as a,a as l}from"./app.94d5b31a.js";const A=JSON.parse('{"title":"前端工程化","description":"","frontmatter":{},"headers":[{"level":2,"title":"Node.js","slug":"node-js","link":"#node-js","children":[{"level":3,"title":"什么是Node.js","slug":"什么是node-js","link":"#什么是node-js","children":[]},{"level":3,"title":"Node.js的应用场景","slug":"node-js的应用场景","link":"#node-js的应用场景","children":[]},{"level":3,"title":"Node.js的参数传递","slug":"node-js的参数传递","link":"#node-js的参数传递","children":[]},{"level":3,"title":"Node中的全局对象","slug":"node中的全局对象","link":"#node中的全局对象","children":[]}]},{"level":2,"title":"模块化开发","slug":"模块化开发","link":"#模块化开发","children":[{"level":3,"title":"模块化的初衷","slug":"模块化的初衷","link":"#模块化的初衷","children":[]},{"level":3,"title":"CommonJS","slug":"commonjs","link":"#commonjs","children":[]}]}],"relativePath":"note/Front-end Engineering.md","lastUpdated":1676027424000}'),e={name:"note/Front-end Engineering.md"},o=l(`
Node.js是一个基于V8 JavaScript引擎的JavaScript运行时环境
可以简单总结出Node.js和浏览器的区别
Chrome浏览器
Blink负责解析HTML文档,遇到JavaScript标签时将内容交给V8引擎
Blink 是 Google Chrome 浏览器的渲染引擎,V8 是 Blink 内置的 JavaScript 引擎
Node.js

process.argv
#process.argv
返回一个数组
process.argv[2]
读取来自命令行的额外参数process.argv[0]
process.argv[1]
分别为node.exe
的绝对路径和目标文件
的绝对路径// sum.js
const x = process.argv[2]
const y = process.argv[3]
console.log(x + y)
# 通过命令行运行node执行脚本 并传入参数
node sum.js 5 10 # 15
console.log
打印内容到stdout并加上换行符console.clear
清空当前stdout中的内容console.trace
打印字符串Trace:
到stderr 在浏览器的控制台选项卡中,我们可以通过输入JS代码与之交互,在Node.js中同样提供了类似的功能
node
即可进入在浏览器中,我们可以在JS代码中访问全局对象window
,代表当前标签窗口
在Node.js中的全局对象名为global
,在控制台输出global
对象:
> global
<ref *1> Object [global] {
global: [Circular *1],
clearInterval: [Function: clearInterval],
clearTimeout: [Function: clearTimeout],
setInterval: [Function: setInterval],
setTimeout: [Function: setTimeout] {
[Symbol(nodejs.util.promisify.custom)]: [Getter]
},
queueMicrotask: [Function: queueMicrotask],
performance: Performance {
nodeTiming: PerformanceNodeTiming {
name: 'node',
entryType: 'node',
startTime: 0,
duration: 2245.9675999991596,
nodeStart: 1.7120999991893768,
v8Start: 7.749699998646975,
bootstrapComplete: 56.47019999846816,
environment: 28.44789999909699,
loopStart: 97.62589999847114,
loopExit: -1,
idleTime: 2070.0206
},
timeOrigin: 1675854922619.539
},
clearImmediate: [Function: clearImmediate],
setImmediate: [Function: setImmediate] {
[Symbol(nodejs.util.promisify.custom)]: [Getter]
}
}
Buffer
clearImmediate
clearInterval
clearTimeout
console
process
queueMicrotask(callback)
setImmediate(callback, [, ...args])
setInterval(callback, delay[, ...args])
setTimeout(callback, delay[, ...args])
TextDecoder
TextEncoder
URL
URLSearchParams
WebAssembly
__dirname
__filename
exports
module
require()
__dirname
当前模块的目录名__filename
当前模块的文件名exports
module
require()
将在模块章节中讲解global
对象 #global
是一个全局对象
process
console
setTimeout
等都有被放入到global
中window
对象上的这无异于增加了开发者的心智负担,所以在最新的ECMA标准中出现了globalThis
,指向全局对象
globalThis
指向window
对象globalThis
指向global
对象两个全局对象的区别:在浏览器中通过var
定义的变量会被放到window
对象上,而Node.js不会
// moduleA.js
const moduleA = (function(){
const name = "Ziu"
const age = 18
const run = () => {
console.log(name + age + 'is running.')
}
return {
name,
age,
run
}
})()
// moduleB.js
console.log(moduleA.name) // 在其他模块中调用
CommonJS是一种规范,当初命名为ServerJS,旨在浏览器以外的地方使用,后为体现其广泛性,改名为CommonJS,简称CJS
规范 是用来指导 实现的
Node
是CommonJS在服务端的代表实现Browserify
是CommonJS在浏览器中的一种实现 (正在被淘汰)WebPack
打包工具具备支持CommonJS的支持和转换所以,Node.js对CommonJS进行了支持和实现,让JavaScript在Node上运行时可以实现模块化开发
.js
文件都是一个单独的模块exports
module.exports
require
// env.js
exports.name = 'Ziu'
exports.age = 18
// utils.js
module.exports = {
sum: function(x, y) {
return x + y
}
}
// index.js
const utils = require('utils.js')
utils.sum(1, 2) // 3
const { sum } = require('utils.js')
sum(1, 2) // 3
const { name, age } = require('env.js')
console.log(name, age) // Ziu 18
exports
的本质 #exports
和require
在Node中的本质
exports
是一个对象,我们可以在这个对象中添加很多属性,添加的属性则会被导出 require
导入时:const env = require('env.js')
env
这个变量等于env.js
中的exports
对象env
是exports
对象的引用赋值// utils.js
exports.a = 0
// 1s后修改a值
setTimeout(() => {
exports.a = 1
}, 1000)
// 2s后检查a值
setTimeout(() => {
console.log(exports.a) // 2
}, 2000)
// index.js
const utils = require('./utils')
console.log(utils.a) // 0
setTimeout(() => {
console.log(utils.a) // 1
utils.a = 2 // 反过来修改a值
}, 1500)
在上述代码中,utils
对象中的属性a
在一秒后被赋值为1
,因此在index.js中输出utils.a
得到了两次不同的结果
反过来,在index.js中修改导入的utils.a
的值后,修改结果也会反映在exports.a
上,输出的值为2
实际开发中不要修改导入模块中的变量,改变原模块中变量的值并不规范
module.exports
#在Node.js中,真正常用的导出方式是module.exports
module.exports
本质上就是exports
对象(同一个内存地址)exports
对象赋值,将需要导出的内容统一导出module.exports
重新赋值,即改变了exports
对象的指向,后续的修改不再影响原模块中的变量const name = 'Ziu'
const run = () => console.log(name + 'is running.')
module.exports = {
name,
run
}
既然如此,为什么还要存在exports
这个概念呢?
module.exports
的概念的Module
类,每一个模块都是Module
的实例,也就是module
exports
,而是module.exports
module
对象中的exports
属性是exports
对象的一个引用 module.exports === exports === utils
如果module.exports
不再引用exports
对象了,修改exports
对象也就没有意义了
// utils.js
module.exports = {
name: 'Ziu'
}
exports.age = 18
// index.js
const utils = require('utils.js')
console.log(utils.name) // Ziu
console.log(utils.age) // undefined
当使用module.exports = { ... }
后,模块中原有的exports
不再被导入识别,导入的内容将变为module.exports
指定的对象内容
require
的本质 #require
是一个函数,可以帮助我们导入一个文件(模块)中导出的对象
.js
后缀,直接使用require('./utils')
index.js
,直接使用require('./tools')
导入tools/index.js
这涉及到require
在匹配路径后的查找规则:
分为三种情况:内置模块、自定义路径、包名
const path = require('path')
const utils = require('./{filename}')
./
../
/
{filename}.js
文件{filename}.json
文件{filename}.node
文件{filename}
作为路径继续查找index
文件 {filename}/index
{filename}/index.js
文件Cannot find module 'xxx'
const lodash = require('lodash')
node_modules
中查找node_modules/{package_name}/index.js
node_modules
找不到则继续向上查找,直到查找到根目录的node_modules
require
的位置相关module
上都有一个属性loaded
loaded === false
表示该模块尚未被加载require
引入时会检查该属性是否为true