Module, Exports, and Require

배경지식

  • commonjs : 모듈을 어떻게 정의하고, 어떻게 사용할 것인가에 대한 명세이다.
  • 일급객체(first class object) : js에서 함수는 일급객체이다. 함수를 문자열이나 숫자처럼 사용할 수 있다. 함수에 인자로 함수를 넣을수도 있다.
  • invoke : 함수를 실행(call)하는것.

모듈(module)

A reuseable block of code whose existence does not accidentally impact other code

모듈은 다른 코드에 직접적으로 영향을 끼치지 않는 코드블록 이다. 자바스크립트는 (존나신기하게도) 예전에는 이게 없었다. es6에서 모듈(module)이라는것이 생겼다. 노드는 여러가지 기능을 모듈을 통해 불러와서 사용한다. 대표적으로 많은 예제에서 처음 배우는 require("http") 이것이 모듈이다.

var http = require('http');

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(3000);

console.log('Server running at http://127.0.0.1:3000/');

이러한 모듈을 직접 만들어 사용할 수 있다.

모듈은 module.exports로 정의하고, require 메서드를 통해 불러온다. require 메서드 사용시 불러올 모듈의 확장자(js)를 생략할수 있다. react에서 자주 볼수있다.

//node core module.js
Module.protype.require = funtion(path){
  return Module._load(path, this)
}
  • requireModule 클래스의 메소드이다.
  • module.exportsrequirereturn값이다.
  • 이런것이 가능한 이유는 노드에 작성하는 코드들은 거~대한 wrapper함수안에 작성되기 때문이다.(module, require , exports등은 모두 파라미터다.)
//(function(exports, require, module, __filename, __dirname){
var hello = function(){
    console.log('Hello ~ Node!");
}

module.exports = hello;
//});

//fn(module.exports, require, module, filename, dirname)

간단한 모듈

모듈의 exports프로퍼티(객체)에 다른코드에서 사용하고자하는 메소드나 프로퍼티를 만들어 내보낼수 있다.

//calc.js
//module 정의

module.exports = {
  add: function(a,b){
    return a + b;
  },
  minus: function(a,b){
    return a - b;
  }
}
//app.js
//module 로드

var calc = require('./calc'); //확장사 생략

var result = calc.add(1,2);
console.log(result);

require 메서드의 인자로 디렉터리를 지정할 수도 있다.

//app.js
var newModule = require('./module');

이렇게 파일이 아닌 폴더만을 지정하면, 그 폴더내의 index.js를 자동으로 지정한다. 이때 index.js내에 다른 모듈(js파일)들을 require해두면 한번의 require로 다른 모듈의 기능들도 사용할 수 있다.

app.js
module/
├──index.js
├──calc.js
└──another.js
//index.js

module.exports = {
  calc: require('./calc'),
  another: require('./another')
}
//app.js
var newModule = require('./module');

var result = newModule.calc.add(1,2);
console.log(result);

실수할수 있는 부분

//greet.js
function Greetr(){
    this.greeting = "hello!"
    this.greet = function(){
        console.log(this.greeting)
    }
}

module.exports = new Greetr();
var greetA = require('./greet.js');
greetA.greet()
greetA.greeting = "Bula~!"

var greetB = require('./greet.js');
greetA.greet()

hello!

Bula!

greetAgreetB는 각각 서로다른 Greetr 클래스의 인스턴스일것 같지만, 실제로는 같다. 이유가 뭘까?

//module.js

var cacheModule = Module._cache[filename]; //같은 filename을 가진 캐쉬가 존재하는지 확인한다.
if(cacheModule){
    //존재한다면 이미존재하는 모듈을 exports한다.
    return cacheModule.exports
}

노드에서는 문서에서 파일(모듈)을 require할때 그 파일을 이미 부른적이있는지 확인하고, 만약 그렇다면(캐쉬에 존재한다면 ) 이전에 불렀던 모듈을 그대로 사용한다.

exports vs module.exports

exportsmodule.exports의 짧은 표현이다. 하지만 항상 같게 동작하는것은 아니다.

exports = function(){
    console.log('changed');
}

console.log(exports); //[Function]
console.log(module.exports); //{} 걍이걸 사용하자

Requiring Native Module

노드(코어)가 내장하고 있는 모듈들을 require메소드를 통해 사용할 수 있다. (참고 https://nodejs.org/api/\)

//module.js

if(NativeModule.exists(filname)){
    return NativeModule.require(filname);
}

util모듈을 사용해보자.

var util = require('util');

var name = "minwoo";
var greeting = util.format('Hello, %s', name);
util.log(greeting);

ES6 Module

안타깝게도 이걸 노드에서 쓰려면 babel을 써야한다.

//greet.js
export funtion greeting(){
    console.log('Hello ~ es6!');
}

/////////////////////

//app.js
import * as greetr from 'greet';

results matching ""

    No results matching ""