모듈이란?
전체를 이루는 부품 하나하나를 의미한다. Node.js에서는 javascript 파일 하나가 모듈이라고 생각하면 편하다.(정확히는 조금 다르다) 이 모듈들이 모여 하나의 프로그램이 된다.
모듈파트에서 눈여겨 볼 점은 하나의 모듈에서 다른 모듈의 기능을 가져다 쓰는 것이 핵심이라는 점이다. 다른 모듈에 존재하는 함수를 사용하려면 모듈을 가져와야 하고, 모듈을 가져오는 것을 "모듈을 로드한다"고 한다.
함수 뿐만 아니라 변수와 같은 것들도 모두 가져와서 사용할 수 있다.
//math-tools.js
function addNum(a, b) {
return a + b;
}
exports.add = add;
맨 마지막 줄에 있는 부분이 모듈을 내보내는 과정인데
'모듈 내부에 있는 add 함수(오른쪽 add)를 모듈 외부에 add라는 이름으로 공개(왼쪽 add)하겠다 '라는 의미이다.
만약 왼쪽 add를 plus로 바꿔준다면 name.js에서 add 함수를 쓸 땐 plus로 써야한다.
모듈을 내보내주었다면 모듈을 가져오는(로드하는) 작업이 필요하다. 필요한 모듈을 가져다 쓸 파일에 다음과 같이 작성함으로써 모듈을 가져올 수 있다.
// name.js
const m = require("./math-tools.js");
console.log(m.add(1,2));
여기서 require은 모듈을 로드해서 객체 1개를 리턴하는 함수인데 require 안에는 가져올 모듈이 들어있는 파일의 경로가 들어가게 된다.
- ./ : 현재의 디렉토리
- ../ : 상위 디렉토리
모듈을 로드할 때, const m = require("./math-tools.js")라고 쓰며 js라는 확장자까지 전부 적어서 사용했지만 실제로는 확장자를 빼고 파일 이름만 적어줘도 잘 실행된다.
주의 사항
모듈이 리턴한 객체를 받을 경우에는 상수 const로 받는 것이 좋다. 모듈이 리턴한 객체를 변수로 받으면 나중에 본인 또는 다른 개발자가 변수 m에 다른 값을 실수로 다시 지정할 수 있어 의도하지 않은 오류가 발생할 수 있기 때문이다.
하나의 객체로 모아서 외부에 공개하기
이전에 함수 뿐만 아니라 다른 변수와 같은 정보들을 모두 내보낼 수 있는 것이 모듈이라고 했다.
그렇다면 내보내고 싶은 것들은 어떻게 한 번에 내보낼 수 있을까?
우선, 공개하고 싶은 것들을 모아서 하나의 객체로 만든다. 그 후 module.exports로 객체를 통째로 공개하면 된다.
만약 공개하고 싶은 것들이 많다면 두 번째 방법을 사용하는 것이 좋다.
let calculator = {
PI = 3.14,
add : (a,b) => a + b,
subtract : (a,b) => a - b,
multiply : (a,b) => a * b,
divide : (a,b) => a / b,
};
module.exports = calculator;
Module wrapper function
지금까지는 어떻게 모듈을 내보내고 로드하는지 알아보았다면 이제부터는 어떤 원리로 모듈을 내보내고 받아오는지에 대해 알아보려고 한다.
Node.js가 모듈을 로드할 때는, Module wrapper function이라는 작업을 해준다(자동으로 되는 작업이다). 이것은 모듈 내의 전체 코드를 감싸주는 작업이다.
이름에서 볼 수 있듯이 Module wrapper function이란 말 그대로 모듈을 감싸주는 코드를 의미하는데 아래와 같이 생겼다.
(function (exports, require, module, _filename, _dirname) {
// 모듈 코드
});
Module wrapper function 은 5개의 인자를 가지는 함수라는 것을 확인할 수 있다.
앞의 add function에 대입해보면 다음과 같다.
(function (exports, require, module, __filename, __dirname) {
function add(a, b) {
return a + b;
}
exports.add = add;
});
이때, console.dir 로 exports와 module을 찍어보기 위해 코드를 살짝 변경한 뒤 확인해보도록 하자.
function add(a, b) {
return a + b;
}
console.log('exports ------------------------->');
console.dir(exports);
console.log('require ------------------------->');
console.dir(require);
console.log('module ------------------------->');
console.dir(module);
console.log('__filename ------------------------->');
console.dir(__filename);
console.log('__dirname ------------------------->');
console.dir(__dirname);
(1) exports 객체
(2) module 객체
exports 객체는 안에 아무 프로퍼티(속성)도 없는 텅 비어있는 객체이고, module 객체는 다양한 프로퍼티를 갖고 있는 객체이다. module객체 안을 자세히 보면, export라는 프로퍼티가 있고, 그 프로퍼티가 빈 객체 하나를 가리키고 있다.
여기에서 의미하는 바, 핵심에 대해서 설명해보겠다.
export 객체와 module 객체의 exports 프로퍼티가 가리키는 객체는 '동일한 객체이다. 그리고 우리가 모듈 내부의 것들을 외부로 공개하기 위해 exports나 moudle.exports를 썼던 것은 바로 이 객체에 접근하기 위해서 쓴 것이었다.
정말로 이게 맞는지 실험해보기 위해 add함수를 plus라는 이름으로 공개해보겠다.
//math-tools.js
function add(a, b) {
return a + b;
}
exports.plus = add; // add 함수를 plus라는 이름으로 공개
console.log('exports ------------------------->');
console.dir(exports);
console.log('require ------------------------->');
console.dir(require);
console.log('module ------------------------->');
console.dir(module);
console.log('__filename ------------------------->');
console.dir(__filename);
console.log('__dirname ------------------------->');
console.dir(__dirname);
math-tools.js 모듈을 다시 실행해보면,
(1) exports 객체
(2) module 객체
exports 객체에는 plus라는 프로퍼티가 추가되었고, 프로퍼티의 값이 add인 함수인 것을 확인할 수 있다.
그리고 module 객체의 exports 프로퍼티가 가리키는 객체도 동일한 객체라고 했으므로 당연히 똑같이 변한 것을 확인할 수 있다.
바로 이 객체가 다른 모듈에서 require 함수로 이 모듈을 로드할 때 리턴되는 객체이다.
그러니까 다른 모듈에서 이 math-tools.js 모듈을
const m = require('./math-tools');
이런 식으로 로드하면, require함수는 exports객체 ( =module 객체의 exports 프로퍼티가 가리키는 객체)를 리턴한다.
'Node.js' 카테고리의 다른 글
Backend -> Frontend로 쿠키 보내기(with Token) (0) | 2023.11.28 |
---|---|
[Node.js] Access Token & Refresh Token 을 이용한 로그인 / 로그아웃 (0) | 2023.11.24 |
Express를 이용해 서버 만들기 (2) | 2023.11.14 |
[Node.js] REPL (1) | 2023.11.10 |
[Node.js] dotenv(.env)란? (1) | 2023.11.07 |