nodeJS學習(9)--- nodeJS模塊:exports vs module.exports

模塊簡介:

經過Node.js的官方API能夠看到Node.js自己提供了不少核心模塊 http://nodejs.org/api/ javascript

  • 這些核心模塊被編譯成二進制文件,能夠 require('模塊名') 去獲取
  • 核心模塊具備最高的加載優先級(有模塊與核心模塊同名時會體現)

(本次主要說自定義模塊)html

 

Node.js還有一類模塊爲文件模塊,能夠是 JavaScript 代碼文件(.js做爲文件後綴)、也能夠是 JSON 格式文本文件(.json做爲文件後綴)、還能夠是編輯過的 C/C++ 文件(.node做爲文件後綴);java

 

文件模塊訪問方式經過require('/文件名.後綴')   ; require('./文件名.後綴')   ; requrie('../文件名.後綴') 去訪問,文件後綴能夠省略;以"/"開頭是以絕對路徑去加載,以"./"開頭和以"../"開頭表示以相對路徑加載,而以"./"開頭表示同級目錄下文件,node

前面提到文件後綴能夠省略,Nodejs 嘗試加載的優先級 js文件 > json文件 > node文件json

 

建立一個自定義模塊

   以一個計數器爲例api

var outputVal  = 0;     //輸出值
var increment = 1;    //增量

/* 設置輸出值 */
function seOutputVal (val) {
    outputVal = val;
}

/* 設置增量 */
function setIncrement(incrementVal){
    increment = incrementVal;
}

/* 輸出 */
function printNextCount()
{    
    outputVal += increment;
    console.log(outputVal) ;
}

function printOutputVal() {
    console.log(outputVal);
}
exports.seOutputVal = seOutputVal;
exports.setIncrement = setIncrement;

module.exports.printNextCount = printNextCount;
自定義模塊 示例源碼

示例中重點在於exports和module.exports;提供了外部訪問的接口,下面調用一下看看效果吧數組

調用自定義模塊

     

/*
    一個Node.js文件就是一個模塊,這個文件多是Javascript代碼、JSON或者編譯過的C/C++擴展。
    重要的兩個對象:
    require是從外部獲取模塊
    exports是把模塊接口公開    
*/
var counter = require('./1_modules_custom_counter');

console.log('第一次調用模塊[1_modules_custom_counter]');

counter.seOutputVal(10);               //設置從10開始計數
counter.setIncrement (10);             //設置增量爲10

counter.printNextCount();
counter.printNextCount();
counter.printNextCount();
counter.printNextCount();

/*
    require屢次調用同一模塊不會重複加載
*/
var counter = require('./1_modules_custom_counter');

console.log('第二次調用模塊[1_modules_custom_counter]');
counter.printNextCount();
自定義模式調用 源碼

 

運行能夠發現經過 exports 和 module.exports 對外公開的方法均可以訪問!緩存

示例中能夠看到,我兩次經過require('./1_modules_custom_counter')獲取模塊,可是第二次引用後調用 printNextCount()方法確從60開始~~~app

緣由是node.js經過require,require屢次調用同一模塊不會重複加載,Node.js會根據文件名緩存全部加載過的文件模塊,因此不會從新加載了ide

注意:經過文件名緩存是指實際文件名,並不會由於傳入的路徑形式不同而認會是不一樣的文件

 

在我建立的1_modules_custom_counter文件中有一個printOutputVal()方法,它並無經過exports或module.exports提供對外公開訪問方法,

若是1_modules_load文件中直接訪問運行會出現什麼樣的狀況呢?

答案是:TypeError: Object #<Object> has no method 'printOutputVal'

 

require, exports, module.exports 區別:

  • require 用來加載代碼(模塊),而 exportsmodule.exports 則用來導出代碼。
    exports 是指向的 module.exports 的引用
    module.exports 初始值爲一個空對象 {},因此 exports 初始值也是 {}
    require() 返回的是 module.exports 而不是 exports

 

nodejs中exports與module.exports的區別:

 

API提供瞭解釋 http://nodejs.org/api/modules.html 

Note that exports is a reference to module.exports making it suitable for augmentation only. If you are exporting a single item such as a constructor you will want to use module.exports directly instead
exports 僅僅是 module.exports 的一個地址引用。nodejs 只會導出 module.exports 的指向,若是 exports 指向變了,那就僅僅是 exports 不在指向 module.exports,因而不會再被導出

 

  • Module.exports:若是你想你的模塊是一個 特定的類型 就用 Module.exports
  • exports: 若是你想的模塊是一個 典型的「實例化對象」 就用 exports

原文:http://www.hacksparrow.com/node-js-exports-vs-module-exports.html

參考:http://www.cnblogs.com/kongxianghai/p/3936197.html

http://www.cnblogs.com/zhongweiv/p/nodejs_module.html

 

1. nodejs 模塊中的 exports 對象:你能夠用它建立你的模塊。例如:

假設這是 rocker.js 文件:

# rocker.js 
exports.name = function() {
    console.log('My name is Lemmy Kilmister');
};

則,在另外一文件中,你能夠這樣引用:

var rocker = require('./rocker.js');
rocker.name(); // 'My name is Lemmy Kilmister'

強調:

(1)給 exports 賦值實際上是給 module.exports 這個空對象添加了屬性,eg:

 
 
var name = 'nswbmw'; 
exports.name = name; 
exports.sayName = function() {  console.log(name); } 

# 給 exports 賦值實際上是給 module.exports 這個空對象添加了兩個屬性而已,上面的代碼至關於:
var name = 'nswbmw';
module.exports.name = name; 
module.exports.sayName = function() { console.log(name); }

 

     (2)二者的使用方法不一樣,eg:

使用 exports:

# circle.js -- 使用 exports 定義一個方法
exports.area = function(r) { return r * r * Math.PI; }
# app.js -- 使用上面文件裏定義的方法
var circle = require('./circle');
console.log(circle.area(4)); # 使用,引用的方式:***.area()

使用 Module.exports:

# area.js -- 使用 module.exports 定義方法
module.exports = function(r) { return r * r * Math.PI;
# app.js -- 使用上面文件定義的方法
var area = require('./area'); 
console.log(area(4)); # 直接使用,***()

 

2. Module.exports :

  • Module.exports 纔是真正的接口,exports只不過是它的一個輔助工具。
  • 最終返回給調用的是Module.exports而不是exports。
  • 全部的exports收集到的屬性和方法,都賦值給了Module.exports。固然,這有個前提,就是Module.exports自己不具有任何屬性和方法。若是,Module.exports已經具有一些屬性和方法,那麼exports收集來的信息將被忽略。eg:修改 rocker.js 以下:
    # 修改的 rocker.js
    module.exports = 'ROCK IT!'; # 將 module.exports = {}; 變爲了 module.exports = ''; exports.name = function() { console.log('My name is Lemmy Kilmister'); };

    此時,再次引用執行 rocker.js 以下:

    var rocker = require('./rocker.js');
    rocker.name(); // TypeError: Object ROCK IT! has no method 'name'
    # 發現報錯:對象「ROCK IT!」沒有name方法 

    rocker 模塊忽略了 exports 收集的 name 方法,返回了一個字符串「ROCK IT!」。由此可知,你的模塊並不必定非得返回「實例化對象」。你的模塊能夠是任何合法的javascript對象--boolean, number, date, JSON, string, function, array等等。

  • 你的模塊能夠是任何你設置給它的東西。若是你沒有顯式的給 Module.exports 設置任何屬性和方法,那麼你的模塊就是 exports 設置給 Module.exports 屬性。

  eg1: 你的模塊是一個類

# 再次修改 rocker.js
module.exports = function(name, age) { this.name = name; this.age = age; this.about = function() { console.log(this.name +' is '+ this.age +' years old'); }; };

能夠這樣使用它:

var Rocker = require('./rocker.js');
var r = new Rocker('Ozzy', 62);
r.about(); // Ozzy is 62 years old

 

eg2: 你的模塊是一個數組

# 再次修改 rocker.js
module.exports = ['Lemmy Kilmister', 'Ozzy Osbourne', 'Ronnie James Dio', 'Steven Tyler', 'Mick Jagger'];

能夠這樣使用它:

var rocker = require('./rocker.js');
console.log('Rockin in heaven: ' + rocker[2]); //Rockin in heaven: Ronnie James Dio

 

     如今你明白了,若是你想你的模塊是一個特定的類型就用 Module.exports,直接 變量/new方法 使用。若是你想的模塊是一個典型的「實例化對象」就用 exports,需引用使用 .***

  • 給Module.exports添加屬性相似於給exports添加屬性。例如:
    module.exports.name = function() {
        console.log('My name is Lemmy Kilmister');
    };

    一樣, exports 是這樣的:

    exports.name = function() {
        console.log('My name is Lemmy Kilmister');
    };

    強調:這兩種定義效果並不相同(本人仍是有點暈,後續將繼續學習)。前面已經提到 module.exports 是真正的接口,exports 只不過是它的輔助工具。推薦使用 exports 導出,除非你打算從原來的 「實例化對象」 改變成一個 類型!!

 

exports和module.exports 覆蓋

上面也也基本明白了exports和module.exports的關係和區別,但若是同時針對printNextCount()方法存在exports和module.exports,結果如何?

調用結果

從結果能夠看出,並無報錯,表示能夠這麼定義,但最終 module.exports 覆蓋了exports

 

****雖然結果不會報錯,若是這麼用開發中不免會有一些問題存在,因此****

1. 最好別分別定義 module.exports 和 exports

2. NodeJs 開發者建議導出對象用 module.exports, 導出多個方法和變量用 exports

其它...

   API中還提供了其它的方法,就不細講了,在上面例子的基礎上自已動手一輸出就知道了

module.id:返回string類型的模塊標識,通常爲徹底解析後的文件名

module.filename:返回一個string類型的徹底解析後文件名

module.loaded:返回一個bool類型,表示是否加載完成

module.parent:返回引用該模塊的模塊

module.children:返回該模塊引用的全部模塊對象的數組
相關文章
相關標籤/搜索