NodeJs require(),exports,module.exports (Part.2)

신세원·2020년 10월 11일
0

앞에서 require(),exports,module.exports의 개념들과 각각의 차이점에 대해 알아보았다.

이번 시간에는 조금 더 깊이 들어가서 자세히 알아보기로 하자.

1. exports

모듈은 독립적인 파일 스코프를 갖기 때문에 모듈 안에 선언한 모든 것들은 그 모듈 내부에서만 참조 가능하다.

모듈안에 선언한 항목을 외부에 공개하여 다른 모듈들이 사용하고 싶게 만들고 싶다면 exports 객체를 사용하여야 한다.

모듈을 파일로 작성하고 외부에 공개할 대상을 exports 객체의 프로퍼티 또는 메소드를 정의한다.

그리고 모듈을 전역 함수 require()를 이용하여 추출한다.

//circle.js
const {PI} = Math; //3.1415926535 8979323846 2643383279...

exports.area = (r) => PI * r * r;

exports.circumference = (r) => 2 * PI * r;

circle.js는 하나의 독립적인 스코프를 갖는 모듈이다. circle 모듈에서 area와 circumference를 export의 객체의 메소드로 정의 하였다.

변수 PI는 circle 모듈에서만 유효한 변수가 되고, area,circumference는 외부에 공개된다.

require 함수를 사용하여 임의의 이름으로 circle 모듈을 import한다. 모듈의 확장자는 생략할 수 있다.

// app.js
const circle = require('./circle.js'); // == require('./circle')

console.log(`지름이 4인 원의 면적: ${circle.area(4)}`);
console.log(`지름이 4인 원의 둘레: ${circle.circumference(4)}`);

이때 circle 모듈은 객체로 반환된다. app.js를 실행시켜 보자.

$ node app
지름이 4인 원의 면적: 50.26548245743669
지름이 4인 원의 둘레: 25.132741228718345

2. module.exports

exports 객체는 프로퍼티 또는 메소드를 여러개 정의할 수 있었다.

하지만 module.exports에는 하나의 값(원시타입,함수,객체)을 할당할 수 있다.

// circle.js
const { PI } = Math;

module.exports = function (r) {
  return {
    area() { return PI * r * r; },
    circumference() { return 2 * PI * r}
  };

circle 모듈의 module.exports에는 하나의 함수를 할당하였지만, 내부에는 여러개의 리턴 값이 있다.

// app.js
const circle = require('./circle');
const myCircle = circle(4);

console.log(`지름이 4인 원의 면적: ${myCircle.area()}`);
console.log(`지름이 4인 원의 둘레: ${myCircle.circumference()}`);

require()함수를 통해 circle 모듈을 임포트하여, circle 변수에 할당하였다.

이때 circle 변수는 circle 모듈에서 module.exports에 할당한 값 자체 즉, 객체를 반환하는 함수이다.

// primitive.js
const pv = 'primitive value';
module.exports = pv;
// app.js
const value = require('./primitive');
console.log(value); // => 'primitive value'

exports와 module.exports는 혼동하기 쉽다.

exports는 module.exports에의 참조이며 module.exports의 alias이다.

즉, exports는 module.exports와 같다고 보아도 무방하다.

구분모듈 정의 방식require 함수 호출 결과
exportsexports 객체에는 값을 할당할 수 없고 공개할 대상을 exports 객체에 프로퍼티 또는 메소드로 추가한다.exports 객체에 추가한 프로퍼티와 메소드가 담긴 객체가 전달된다.
module.exportsmodule.exports 객체에 하나의 값(원시 타입, 함수, 객체)만을 할당한다.module.exports 객체에 할당한 값이 전달된다.

2. module.exports에 함수를 할당하는 방식

// foo.js
module.exports = function(a, b) {
  return a + b;
};
// app.js
const add = require('./foo');

const result = add(1, 2);
console.log(result); // => 3

module.exports는 1개의 값만을 할당할 수 있다. 그렇다면 여러개의 값을 할당할 수는 없을까?

다음과 같이 객체를 사용하여 복수의 기능을 하나로 묶어 공개하는 방식을 사용할 수 있다.

// foo.js
module.exports = {
  add (v1, v2) { return v1 + v2 },
  minus (v1, v2) { return v1 - v2 }
};
// app.js
const calc = require('./foo');

const result1 = calc.add(1, 2);
console.log(result1); // => 3

const result2 = calc.minus(1, 2);
console.log(result2); // => -1

3. require

require 함수의 인수에는 파일 뿐만 아니라 디렉터리를 지정할 수도 있다.

예를 들어 다음 디렉터리 구조의 경우를 살펴보자.

project/
├── app.js
└── module/
    ├── index.js
    ├── calc.js
    └── print.js

아래와 같이 모듈을 명시하지 않고 require 함수를 호출하면 해당 디렉터리의 index.js를 로드한다.

const myModule = require('./module');

이때 로드되는 index.js 내에서 calc.js과 print.js를 require하면 한번의 require로 calc.js과 print.js의 모든

기능을 사용할 수 있다.

// module/index.js
module.exports = {
  calc: require('./calc'),
  print: require('./print')
};
// module/calc.js
module.exports = {
  add (v1, v2) { return v1 + v2 },
  minus (v1, v2) { return v1 - v2 }
};
// module/print.js
module.exports = {
  sayHello() { console.log('Hi!') }
};
// app.js
const myModule = require('./module');

// module/calc.js의 기능
const result = myModule.calc.add(1, 2);

console.log(result);

// module/print.js의 기능
myModule.print.sayHello();
profile
생각하는대로 살지 않으면, 사는대로 생각하게 된다.

0개의 댓글