Node.js의 모듈 시스템 이해
관련 추천: "node js tutorial"
Node.js
JavaScript의 모듈은 웹 페이지에 대화형 기능을 추가하기 위한 간단한 스크립트 언어로 나왔습니다. 처음에는 모듈 시스템이 포함되어 있지 않았습니다. JavaScript는 점점 더 복잡해지는 문제를 해결합니다. 모든 코드를 하나의 파일에 작성하고 기능 단위를 구별하는 기능을 사용하면 더 이상 복잡한 애플리케이션 개발을 지원할 수 없습니다. ES6은 대부분의 고급 언어에 공통적인 클래스와 모듈을 제공하므로 개발자가 더 쉽게 구성할 수 있습니다.
import _ from 'lodash'; class Fun {} export default Fun;
위 세 줄의 코드는 모듈 시스템의 가장 중요한 두 가지 요소인 가져오기와 내보내기를 보여줍니다.
내보내기
는 모듈의 외부 인터페이스를 지정하는 데 사용됩니다export
用于规定模块的对外接口import
用于输入其他模块提供的功能
而在 ES6 之前,社区出现了很多模块加载方案,最主要的有 CommonJS 和 AMD 两种,Node.js 诞生早于 ES6,模块系统使用的是类似 CommonJS 的实现,遵从几个原则
一个文件是一个模块,文件内的变量作用域都在模块内
使用
module.exports
对象导出模块对外接口使用
require
引入其它模块
circle.js
const { PI } = Math; module.exports = function area(r) { PI * r ** 2; };
上面代码就实现了 Node.js 的一个模块,模块没有依赖其它模块,导出了方法 area
计算圆的面积
test.js
const area = require('./circle.js'); console.log(`半径为 4 的圆的面积是 ${area(4)}`);
模块依赖了 circle.js,使用其对外暴露的 area 方法,计算圆的面积
module.exports
模块对外暴露接口使用 module.exports,常见的有两种用法:为其添加属性或赋值到新对象test.js
// 添加属性 module.exports.prop1 = xxx; module.exports.funA = xxx; module.exports.funB = xxx; // 赋值到全新对象 module.exports = { prop1, funA, funB, };
两种写法是等价的,使用时候没区别
const mod = require('./test.js'); console.log(mod.prop1); console.log(mod.funA());
还有另外一种直接使用 exports
对象的方法,但是只能对其添加属性,不能赋值到新对象,后面会介绍原因
// 正确的写法:添加属性 exports.prop1 = xxx; exports.funA = xxx; exports.funB = xxx; // 赋值到全新对象 module.exports = { prop1, funA, funB, };
require('id')
模块类型
require 用法比较简单,id 支持模块名和文件路径两种类型
模块名
const fs = require('fs'); const _ = require('lodash');
示例中的 fs、lodash 都是模块名,fs 是 Node.js 内置的核心模块,lodash 是通过 npm 安装到 node_modules
下的第三方模块,如果出现重名,优先使用系统内置模块
因为一个项目内可能会包含多个 node_modules 文件夹(Node.js 比较失败的设计),第三方模块查找过程会遵循就近原则逐层上溯(可以在程序中打印 module.paths
查看具体查找路径),直到根据 NODE_PATH
环境变量查找到文件系统根目录,具体过程可以参考官方文档
此外,Node.js 还会搜索以下的全局目录列表:
- $HOME/.node_modules
- $HOME/.node_libraries
- $PREFIX/lib/node
其中 $HOME
是用户的主目录, $PREFIX
是 Node.js 里配置的 node_prefix
。强烈建议将所有的依赖放在本地的 node_modules 目录,这样将会更快地加载,且更可靠
文件路径
模块还可以可以使用文件路径加载,这是项目内自定义模块的通用加载方式,路径可以省略拓展名,会按照 .js、.json、.node 顺序尝试
- 以
'/'
为前缀的模块是文件的绝对路径,按照系统路径查找模块 - 以
'./'
为前缀的模块是相对于当前调用 require 方法的文件,不受后续模块在哪里被使用到影响
单次加载 & 循环依赖
模块在第一次加载后会被缓存到 Module._cache
,如果每次调用 require('foo')
都解析到同一文件,则返回相同的对象,同时多次调用 require(foo)
不会导致模块的代码被执行多次。 Node.js 根据实际的文件名缓存模块,因此从不同层级目录引用相同模块不会重复加载。
理解的模块单次加载机制方便我们理解模块循环依赖后的现象a.js
console.log('a 开始'); exports.done = false; const b = require('./b.js'); console.log('在 a 中,b.done = %j', b.done); exports.done = true; console.log('a 结束');
b.js
console.log('b 开始'); exports.done = false; const a = require('./a.js'); console.log('在 b 中,a.done = %j', a.done); exports.done = true; console.log('b 结束');
main.js
li>
import
는 다른 모듈에서 제공하는 기능을 가져오는 데 사용됩니다
ES6 이전에는 커뮤니티에 많은 모듈 로딩 솔루션이 등장했는데 가장 중요한 솔루션은 CommonJS와 AMD와 Node.js가 탄생했습니다. ES6 이전에는 모듈 시스템이 CommonJS와 유사한 구현을 사용하여 여러 원칙을 따릅니다
파일은 모듈이고 파일의 변수 범위는 모듈 내에 있습니다
🎜🎜module .exports
객체 내보내기 모듈 외부 인터페이스 사용🎜🎜🎜require
를 사용하여 다른 모듈 도입🎜 🎜circle.js
🎜console.log('main 开始'); const a = require('./a.js'); const b = require('./b.js'); console.log('在 main 中,a.done=%j,b.done=%j', a.done, b.done);
area
메소드를 내보내서 면적을 계산합니다. 원🎜🎜test.js
🎜main 开始 a 开始 b 开始 在 b 中,a.done = false b 结束 在 a 中,b.done = true a 结束 在 main 中,a.done=true,b.done=true
module.exports🎜🎜모듈의 외부에 노출된 인터페이스는 module.exports를 사용합니다. 두 가지 일반적인 사용법이 있습니다: 새 객체에 속성을 추가하거나 값을 할당합니다🎜test.js
🎜(function(exports, require, module, __filename, __dirname) {
// 模块的代码实际上在这里
});
로그인 후 복사로그인 후 복사🎜둘 작성 방법은 동일하며 사용시 차이가 없습니다🎜const exports = module.exports;
(function(exports, require, module, __filename, __dirname) {
// 模块的代码实际上在这里
});
로그인 후 복사로그인 후 복사🎜exports 개체 방법을 직접 사용하는 방법도 있지만 속성만 추가할 수 있고 새 개체에 할당할 수는 없습니다. 이유는 나중에 소개하겠습니다🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">{
"presets": [
["@babel/preset-env", {
"targets": {
"node": "8.9.0",
"esmodules": true
}
}]
]
}</pre><div class="contentsignin">로그인 후 복사</div></div><div class="contentsignin">로그인 후 복사</div></div>
<h2 id="requireid">require('id')🎜<h3 id="Module-type">Module type</h3>🎜require 사용법은 비교적 간단하며 id는 두 가지 유형을 지원합니다. 모듈 이름 및 파일 경로🎜<h4 id="모듈-이름">모듈 이름</h4>rrreee🎜fs와 예제의 lodash는 모두 모듈 이름입니다. fs는 Node.js에 내장된 핵심 모듈이고 lodash는 npm을 통해 <code>node_modules
아래에 설치된 타사 모듈. 중복된 이름이 있는 경우 프로젝트에 여러 node_modules 폴더가 포함될 수 있으므로 시스템 내장 모듈을 사용하는 것이 우선입니다(상대적으로 실패한 설계). Node.js), 타사 모듈 검색 프로세스는 근접성 원칙을 따르고 계층별로 올라갑니다(특정 검색 경로를 보려면 프로그램에서 module.paths
를 인쇄할 수 있음). NODE_PATH
환경 변수에 따라 파일 시스템 루트 디렉터리를 찾으세요. 특정 프로세스는 공식 문서를 참조하세요🎜🎜또한 Node.js는 다음 전역 디렉터리 목록도 검색합니다.🎜🎜$HOME/.node_modules 🎜$HOME/.node_libraries🎜$PREFIX/lib/node🎜여기서 $HOME
는 사용자의 홈 디렉터리인 $ PREFIX
는 Node.js에 구성된 node_prefix
입니다. 모든 종속성을 로컬 node_modules 디렉터리에 배치하는 것이 좋습니다. 이렇게 하면 더 빠르게 로드되고 더 안정적이 됩니다.🎜파일 경로
🎜모듈은 파일 경로를 사용하여 로드할 수도 있습니다. 프로젝트의 커스텀 모듈에 대한 일반적인 로딩 방법은 경로 확장을 생략할 수 있으며, '/'
접두사가 붙은 모듈은 .js, .json, .node🎜🎜 파일의 절대 경로이며, 시스템 경로에 따라 모듈을 검색합니다.🎜 './'
접두사가 붙은 모듈은 현재 require 메소드를 호출하는 파일에 상대적이며, 후속 모듈이 사용되는 위치에 영향을 받지 않습니다.단일 로드 및 순환 종속성
🎜모듈은 첫 번째 로드 ._cache
이후 모듈, require('foo')
에 대한 각 호출이 동일한 파일로 확인되면 동일한 객체가 반환되고 require(foo)
는 여러 번 호출됩니다. > 모듈의 코드가 여러 번 실행되지 않습니다. Node.js는 실제 파일 이름을 기반으로 모듈을 캐시하므로 다른 디렉터리 수준에서 참조할 때 동일한 모듈이 두 번 로드되지 않습니다. 🎜🎜잘 알려진 모듈 단일 로딩 메커니즘은 모듈 순환 종속성 현상에 대한 이해를 돕습니다🎜a.js
🎜rrreee🎜b.js
🎜rrreee🎜 main.js
:🎜rrreee🎜main.js가 a.js를 로드하면 a.js는 b.js를 로드합니다. 이때 b.js는 무한 루프를 방지하기 위해 a.js를 로드하려고 합니다. , a.js의 내보내기 개체의 🎜미완성 복사본🎜이 b.js 모듈에 제공된 다음 b.js가 로드를 완료하고 내보내기 개체를 a.js 모듈🎜🎜에 제공하므로 다음의 출력이 반환됩니다. 예는 🎜main 开始
a 开始
b 开始
在 b 中,a.done = false
b 结束
在 a 中,b.done = true
a 结束
在 main 中,a.done=true,b.done=true
로그인 후 복사로그인 후 복사
(function(exports, require, module, __filename, __dirname) { // 模块的代码实际上在这里 });
const exports = module.exports; (function(exports, require, module, __filename, __dirname) { // 模块的代码实际上在这里 });
main 开始 a 开始 b 开始 在 b 中,a.done = false b 结束 在 a 中,b.done = true a 结束 在 main 中,a.done=true,b.done=true
看不懂上面的过程也没关系,日常工作根本用不到,即使看懂了也不要在项目中使用循环依赖!
工作原理
Node.js 每个文件都是一个模块,模块内的变量都是局部变量,不会污染全局变量,在执行模块代码之前,Node.js 会使用一个如下的函数封装器将模块封装
(function(exports, require, module, __filename, __dirname) { // 模块的代码实际上在这里 });
- __filename:当前模块文件的绝对路径
- __dirname:当前模块文件据所在目录的绝对路径
- module:当前的模块实例
- require:加载其它模块的方法,module.require 的快捷方式
- exports:导出模块接口的对象,module.exports 的快捷方式
回头看看最开始的问题,为什么 exports 对象不支持赋值为其它对象?把上面函数添加一句 exports 对象来源就很简单了
const exports = module.exports; (function(exports, require, module, __filename, __dirname) { // 模块的代码实际上在这里 });
其它模块 require 到的肯定是模块的 module.exports 对象,如果吧 exports 对象赋值给其它对象,就和 module.exports 对象断开了连接,自然就没用了
在 Node.js 中使用 ES Module
随着 ES6 使用越来越广泛,Node.js 也支持了 ES6 Module,有几种方法
babel 构建
使用 babel 构建是在 v12 之前版本最简单、通用的方式,具体配置参考 @babel/preset-env(https://babeljs.io/docs/en/babel-preset-env)
.babelrc
{ "presets": [ ["@babel/preset-env", { "targets": { "node": "8.9.0", "esmodules": true } }] ] }
原生支持
在 v12 后可以使用原生方式支持 ES Module
开启
--experimental-modules
模块名修改为
.mjs
(强烈不推荐使用)或者 package.json 中设置"type": module
这样 Node.js 会把 js 文件都当做 ES Module 来处理,更多详情参考官方文档(https://nodejs.org/dist/latest-v13.x/docs/api/esm.html)
更多编程相关知识,请访问:编程视频!!
위 내용은 Node.js의 모듈 시스템 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

이 기사는 NodeJS V8 엔진의 메모리 및 가비지 수집기(GC)에 대한 심층적인 이해를 제공할 것입니다. 도움이 되기를 바랍니다.

Non-Blocking, Event-Driven 기반으로 구축된 Node 서비스는 메모리 소모가 적다는 장점이 있으며, 대규모 네트워크 요청을 처리하는데 매우 적합합니다. 대규모 요청을 전제로 '메모리 제어'와 관련된 문제를 고려해야 합니다. 1. V8의 가비지 수집 메커니즘과 메모리 제한 Js는 가비지 수집 기계에 의해 제어됩니다.

Node용 Docker 이미지를 선택하는 것은 사소한 문제처럼 보일 수 있지만 이미지의 크기와 잠재적인 취약점은 CI/CD 프로세스와 보안에 상당한 영향을 미칠 수 있습니다. 그렇다면 최고의 Node.js Docker 이미지를 어떻게 선택합니까?

Node 19가 정식 출시되었습니다. 이 글에서는 Node.js 19의 6가지 주요 기능에 대해 자세히 설명하겠습니다. 도움이 되셨으면 좋겠습니다!

nodejs 실행 파일을 pkg로 패키징하는 방법은 무엇입니까? 다음 기사에서는 pkg를 사용하여 Node 프로젝트를 실행 파일로 패키징하는 방법을 소개합니다. 도움이 되기를 바랍니다.

파일 모듈은 파일 읽기/쓰기/열기/닫기/삭제 추가 등과 같은 기본 파일 작업을 캡슐화한 것입니다. 파일 모듈의 가장 큰 특징은 모든 메소드가 **동기** 및 ** 두 가지 버전을 제공한다는 것입니다. 비동기**, sync 접미사가 있는 메서드는 모두 동기화 메서드이고, 없는 메서드는 모두 이기종 메서드입니다.

이벤트 루프는 Node.js의 기본 부분이며 메인 스레드가 차단되지 않도록 하여 비동기 프로그래밍을 가능하게 합니다. 이벤트 루프를 이해하는 것은 효율적인 애플리케이션을 구축하는 데 중요합니다. 다음 기사는 Node.js의 이벤트 루프에 대한 심층적인 이해를 제공할 것입니다. 도움이 되기를 바랍니다!

노드가 npm 명령을 사용할 수 없는 이유는 환경 변수가 올바르게 구성되지 않았기 때문입니다. 해결 방법은 다음과 같습니다. 1. "시스템 속성"을 엽니다. 2. "환경 변수" -> "시스템 변수"를 찾은 다음 환경을 편집합니다. 3. nodejs 폴더의 위치를 찾습니다. 4. "확인"을 클릭합니다.
