CommonJs 모듈 시스템에서 "module.exports"와 "exports"의 차이점


277

이 페이지 ( http://docs.nodejitsu.com/articles/getting-started/what-is-require )에서 "내보내기 오브젝트를 함수 또는 새 오브젝트로 설정하려면 다음을 수행해야합니다. module.exports 객체를 사용하십시오. "

내 질문은 이유입니다.

// right
module.exports = function () {
  console.log("hello world")
}
// wrong
exports = function () {
  console.log("hello world")
}

나는 console.logged 결과 ( result=require(example.js))와 첫 번째 [Function]는 두 번째입니다 {}.

그 이유를 설명해 주시겠습니까? Node.js의 module.exports vs exports 게시물을 읽었습니다 . 도움이되지만 그렇게 설계 한 이유는 설명하지 않습니다. 내보내기 참조가 직접 반환되면 문제가 발생합니까?


11
항상 사용하십시오 module.exports.
가브리엘 라마

1
위에서 언급 한 조언을 따르면이 문제를 피할 수 있다고 생각합니다.
Vitalii Korsakov

@GabrielLlamas는 왜 많은 패키지는 사용합니까 exports예를 들어, github.com/tj/consolidate.js/blob/master/lib/consolidate.js ?
CodyBugstein

3
@Imray 항상을 사용 module.exports하면 결코 잘못 exports되지 않지만 기본 내 보낸 객체를 바꾸지 않는 경우, 즉 단순히 다음과 같은 속성을 첨부하는 경우 사용할 수 있습니다 var foo = require('foo').foo. 이 foo속성은 다음 exports.foo = ...과 같이 내보낼 수 있습니다 : 물론 module.exports. 개인적인 선택이지만 현재는 적절하게 사용 module.exports하고 exports있습니다.
Gabriel Llamas 2012

exports.myFunc = function () {}을 선호하므로 파일 맨 아래에 내보내기 목록을 유지할 필요가 없습니다. ES6에서 선언 할 때 내보내기의 일반적인 관행에 더 가깝습니다.
SacWebDeveloper

답변:


625

moduleexports속성 이있는 일반 JavaScript 객체입니다 . exports로 설정되는 일반 자바 스크립트 변수입니다 module.exports. 파일의 끝에서, Node.js를 기본적 것이다 '복귀' module.exports받는 require기능. Node에서 JS 파일을 보는 간단한 방법은 다음과 같습니다.

var module = { exports: {} };
var exports = module.exports;

// your code

return module.exports;

당신의 속성 설정하면 exports같은 exports.a = 9;설정합니다, module.exports.a객체는 자바 스크립트에서 참조, 같은 개체에 여러 변수를 설정하면, 그들이 그 수단으로 주위에 전달되기 때문에뿐만 아니라 입니다 모두 같은 객체를; 그래서 다음 exportsmodule.exports같은 객체입니다.
사용자가 설정하지만 exports뭔가 새로운, 그것은 더 이상 설정되지 않습니다 module.exports때문에, exports그리고 module.exports더 이상 같은 객체입니다.


11
맞습니다. 단지 참조 유형의 기초 일뿐입니다.
Vitalii Korsakov

18
왜!? 왜 여기서 만 읽을 수 있습니까? 모든 모듈 식 자바 스크립트에 대한 태그 라인이어야합니다. 감사합니다
lima_fil

8
아름답게 설명했다!
Aakash Verma

3
굉장한, 최고의 답변!
John

5
좋은 설명입니다. 에 대한 문서 module.exports도 그것을 설명 nodejs.org/api/modules.html#modules_module_exports를
브라이언 Morearty

52

Renee의 답변이 잘 설명되어 있습니다. 예를 들어 답변에 추가 :

노드는 파일에 많은 작업을 수행하며 중요한 것 중 하나는 파일 랩핑입니다. 내부 nodejs 소스 코드 "module.exports"가 리턴됩니다. 한 걸음 물러서서 래퍼를 이해할 수 있습니다. 당신이 가지고 있다고 가정

greet.js

var greet = function () {
   console.log('Hello World');
};

module.exports = greet;

위의 코드는 다음과 같이 nodejs 소스 코드 내에 IIFE (즉시 호출 함수 표현식)로 래핑됩니다.

(function (exports, require, module, __filename, __dirname) { //add by node

      var greet = function () {
         console.log('Hello World');
      };

      module.exports = greet;

}).apply();                                                  //add by node

return module.exports;                                      //add by node

위의 함수가 호출되고 (.apply ()) module.exports가 반환됩니다. 현재 module.exports 및 exports는 동일한 참조를 가리 킵니다.

이제 greet.js를 다음과 같이 다시 작성한다고 가정하십시오.

exports = function () {
   console.log('Hello World');
};
console.log(exports);
console.log(module.exports);

출력은

[Function]
{}

그 이유는 다음과 같습니다. module.exports는 빈 객체입니다. 우리는 module.exports에 아무것도 설정하지 않고 새로운 greet.js에서 exports = function () .....을 설정했습니다. 따라서 module.exports가 비어 있습니다.

기술적으로 수출과 module.exports는 동일한 참조를 가리켜 야합니다 (맞습니다 !!). 그러나 function () ....을 내보내기에 할당 할 때 "="를 사용하여 메모리에 다른 객체를 만듭니다. 따라서 module.exports 및 exports는 다른 결과를 생성합니다. 수출에 관해서는 재정의 할 수 없습니다.

이제 greet.js (Renee 응답 참조)를 다음과 같이 다시 씁니다 (Mutation이라고 함).

exports.a = function() {
    console.log("Hello");
}

console.log(exports);
console.log(module.exports);

출력은

{ a: [Function] }
{ a: [Function] }

보시다시피 module.exports 및 exports는 함수 인 동일한 참조를 가리키고 있습니다. 내보내기에서 속성을 설정하면 JS에서 객체가 참조로 전달되므로 module.exports에서 속성이 설정됩니다.

결론은 혼란을 피하기 위해 항상 module.exports를 사용합니다. 도움이 되었기를 바랍니다. 행복한 코딩 :)


이것 역시 아름다운 통찰력있는 답변이며 @ goto-bus-stop의 답변을 보완합니다. :)
varun

23

또한 이해하는 데 도움이 될 수있는 한 가지 사항 :

math.js

this.add = function (a, b) {
    return a + b;
};

client.js

var math = require('./math');
console.log(math.add(2,2); // 4;

이 경우에는 좋습니다.

console.log(this === module.exports); // true
console.log(this === exports); // true
console.log(module.exports === exports); // true

따라서 기본적으로 "this"는 실제로 module.exports와 같습니다.

그러나 구현을 다음과 같이 변경하면

math.js

var add = function (a, b) {
    return a + b;
};

module.exports = {
    add: add
};

이 경우 새 오브젝트가 작성되었으므로 "this"는 더 이상 module.exports와 같지 않습니다.

console.log(this === module.exports); // false
console.log(this === exports); // true
console.log(module.exports === exports); // false

그리고 이제 require에 의해 리턴되는 것은 더 이상이 아니라 export.modules에 정의 된 것입니다.

다른 방법은 다음과 같습니다.

math.js

module.exports.add = function (a, b) {
    return a + b;
};

또는:

math.js

exports.add = function (a, b) {
    return a + b;
};

15

Rene의 답변 exports과 의 관계에 대한 대답은 module.exports분명합니다. 모든 것이 자바 스크립트 참조에 관한 것입니다. 그냥 추가하고 싶습니다 :

우리는 이것을 많은 노드 모듈에서 볼 수 있습니다 :

var app = exports = module.exports = {};

이를 통해 module.exports를 변경하더라도 두 변수가 동일한 객체를 가리 키도록하여 내보내기를 계속 사용할 수 있습니다.


나는이 설명과 혼동되어 정교하게 친절 했습니까?
GuyFreakz

6
@GuyFreakz 확실이 당신의 혼란을 말하는 경우 아니지만 module.exportsexports같은 객체를 참조하는 초기화 단지 별도의 변수입니다. 하나의 변수 참조를 변경하면 두 변수는 더 이상 같은 것을 참조하지 않습니다. 위의 코드 줄은 두 변수가 모두 동일한 새 객체로 초기화되도록합니다.
앤드류 팔머

다른 사람들이 @fengshuo를 놓친 실제 사용 사례. 감사!
Aakash Verma

0

myTest.js

module.exports.get = function () {};

exports.put = function () {};

console.log(module.exports)
// output: { get: [Function], put: [Function] }

exportsmodule.exports같은 동일한 개체에 대한 참조이다. 편의에 따라 두 가지 방법으로 속성을 추가 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.