1. 모듈이란?
모듈이란 "독립된 기능을 갖는 것(함수, 파일)들의 모임" 이다. 옛날 방식인 절차 지향으로 모든 기능을 써내려 가는 것보다, 기능 별로 함수를 만들어 함수를 호출하는 방식으로 프로그래밍을 하면 유지 보수가 훨씬 편해진다. 이러한 모듈 개념을 Node.js에서 사용하고 있다.
모듈은 Node.js에서 제공하는 것이 있고, 또는 누군가가 만들어 놓은 모듈이 있으며, 직접 만들 수도 있다. 모듈을 라이브러리화 시켜서 깃헙에 올릴 수도 있고, 비즈니스 로직에 따라 모듈을 만들어 사용할 수도 있고 굉장히 자유롭다.
모듈은 2가지로 나눌 수 있다.
- 외장 모듈
- 내장 모듈
2. 직접 모듈 만들고 불러오기
모듈을 생성하기 위해서는 exports 전역 객체를 사용하고, 모듈을 불러오기 위해서는 require() 메서드를 사용한다.
1) 모듈 생성하기
모듈을 생성하는 방법으로 2가지가 있다.
calc.js 파일을 만들어서 아래와 같이 작성한다.
// 첫 번째 방법 : exports에 직접 프로퍼티를 설정
exports.add = function (a, b) {
return a + b;
}
exports.multiply = function (a, b) {
return a * b;
}
exports 객체에 직접 add와 multiply 프로퍼티를 추가하는 방법이다.
다음은 calc라는 빈 객체를 생성한 후에 calc 객체에 add와 multiply 프로퍼티를 추가한 후, module.exports 에 calc 객체를 할당하는 방법이다.
// 두 번째 방법 : 새로운 객체에 프로퍼티를 설정 후 module.export에 할당하기
var calc = {};
calc.add = function (a, b) {
return a + b;
}
calc.multiply = function (a, b) {
return a * b;
}
module.exports = calc;
두 방법 모두 모듈을 생성하는 방법이다. 즉, calc.js 파일은 모듈이다.
그런데 exports 객체에 직접 프로퍼티를 할당하는 방법(첫번째 방법)과 module.exports에 객체를 할당하는 방법(두번째 방법)은 조금 차이가 있다. 일반적으로 후자의 방법을 많이 사용한다.
2) 모듈 불러오기
다음으로 app.js 에서 위에서 작성한 모듈을 불러와 보도록 한다.
// calc2.js 파일 불러오기
// require()는 exports 객체를 반환한다.
var calc2 = require("./modules/calc2");
console.log("calc.add(3, 5) : " + calc.add(3, 5));
console.log("calc.multiply(3, 5) : " + calc.multiply(3, 5));
모듈을 불러오기 위해서는 require() 함수를 호출하면 되고, 인자로 파일 경로( ./modules/calc2 )를 전달한다. 파일 경로는 확장자인 .js를 생략하고 파일명만 전달해도 된다.
require() 함수의 반환 값은 exports 객체이며, calc 변수는 exports 객체처럼 사용할 수 있다. 즉, calc.js에서 exports에 add와 multiply 프로퍼티를 추가했었기 때문에, calc 변수 역시 add와 multiply 프로퍼티를 갖고 있다.
3) 실행
이제 테스트를 위해 커맨더 창에서 아래의 명령어를 실행한다.
# node app.js
app.js에서 calc2 모듈을 불러오는 것이므로 실행 파일은 calc2.js가 아닌 app.js이다.
3. exports vs module.exports
"모듈 생성하기"은 모듈을 정의하는 두 가지 방법에 대해 말해준다. 이번에는 두 방식에 차이에 대해 살펴볼 것인데, 결론적으로 "두 번째 방법"인 module.exports를 사용해서 객체를 할당해주는 것이 더 좋다.
1) 객체 할당 불가
"첫 번째 방법"처럼 exports를 사용할 경우, exports에 직접 객체를 할당할 수 없다. "2. 기존의 exports를 새로운 객체로 지정하기"에서 보았던 것처럼 에러가 발생한다.
2) module.exports에 의해 무시
user.js
module.exports = {
name: "Rudy",
age: 25
}
exports.name = "HotGarlic";
app.js
var user = require("./user");
console.log(user.name);
결과
user.js에 module.exports와 exports에서 동시에 name 프로퍼티를 추가했을 경우, 실행 결과는 "Rudy"이다. 즉, exports.name="HotGarlic"는 무시되었다.
그 이유는 exports는 단순히 module.exports를 참조할 뿐이며, exports에서 할당된 프로퍼티는 require()에서 module.exports에 추가되도록 처리된다.
4. module.exports에 함수 할당하기
지금까지 requrie()로 모듈을 불러올 때 모두 객체를 전달받았다. 모듈은 반환할 때 객체 뿐만 아니라 함수를 반환할 수도 있다.
function.js
module.exports = function () {
return "function";
};
app.js
var function_ = require("./modules/function");
console.log(function());
결과
자바스크립트에서는 함수도 객체이므로 당연한 결과이다.
간단하게 정리해보면,
- 모듈 생성하기
- exports / module.exports
- exports는 module.exports를 참조한다.
- 일반적으로 module.exports를 통해 모듈을 생성한다.
- exports / module.exports
- 모듈 불러오기
- require("모듈 파일 경로")