2014-06-17 93 views
1

好的問題很簡單。我想使用兩個JavaScript文件:一個在模塊模式之後,另一個在調用第一個文件。我使用Node.js測試了所有的代碼。當所有的代碼都在一個文件中,但是如果我將代碼分成兩個文件,我會得到一個錯誤。使用Javascript的Javascript模塊

下面的代碼:

// module.js 

var testModule = (function(){ 
"use strict"; 

var counter = 0; 

return { 
    incrementCounter : function(){ 
     return counter++; 
    }, 
    resetCounter : function(){ 
     console.log("Last Counter Value before RESET :" + counter); 
     counter = 0; 
    }; 
}; 

})(); 

// script.js 

var testModule = require('./module.js'); // i'm not sure about require or import 
"use strict"; 

testModule.incrementCounter(); 
testModule.resetCounter(); 

PS:我想使用JavaScript符號不是節點出口符號來實現該模式。

+2

您的代碼格式不正確且包含錯誤。如果你修復它,我可能會考慮幫助你。 –

+0

好的...我修好了!只複製粘貼錯誤...對胖手指抱歉! ahaha – cicciosgamino

回答

2

我首先會說不清楚爲什麼要在Node.js中使用「模塊模式」。我的意思是,您建議的模塊模式在客戶端JavaScript中更具意義,即瀏覽器中的JavaScript,但是如果您的代碼旨在在Node.js中運行,那麼您可以利用已存在於Node中的模塊功能而且我個人認爲在這種情況下強制使用模塊模式是沒有價值的。因此,我將首先以不同的方式深入研究使用Node.js模塊模式,並在最後解釋如何組合「模塊模式」和「Node.js模塊模式」。

核心模塊,導入和導出

讓我們從最明顯和最簡單的事情開始。自從使用Node的第一天起,可能每個人都在學習:每個代碼文件都被認爲是一個模塊。我們聲明的變量,屬性,函數,構造函數對模塊是私有的,除非模塊的程序員明確地向公衆公開它們,否則其他模塊不能訪問它們或使用它們;即默認情況下,我們在模塊內部聲明的所有內容都被封裝並隱藏在外部世界中,除非另有明確說明。爲了揭示程序員可以訪問的一個特殊對象module,它有一個叫做exports的特殊屬性。您在module.exports對象中發佈的所有內容均可供其他模塊公開使用。例如,在下面的代碼中,變量pi對任何其他模塊都是不可訪問的,但是foo.js,而名爲bar的屬性公開可用於導入模塊foo.js的任何其他模塊。請注意,這與Node.js中的JavaScript與JavaScript中的JavaScript進行比較時的基本區別,JavaScript在瀏覽器中執行,JavaScript文件中的功能可能會在全局對象中公開顯示(即window)。

//module foo.js 
var pi = 3.14; 
module.exports.bar = 'Hello World'; 

現在第二模塊baz.js可以「進口」的模塊foo.js並獲得財產bar訪問。在Node中,我們通過使用名爲require的全局函數來實現此效果。有些如下:

//module baz.js 
var foo = require('./foo'); 
console.log(foo.bar); //yields Hello World 

技術1 - 擴展出口具有附加功能對象

因此,一種技術,以暴露一個模塊中的功能由在增加功能和屬性到module.exports對象。在這種情況下,Node提供對exports對象的直接訪問,以使我們更簡單。例如:

//module foo.js 
exports.serviceOne = function(){ }; 
exports.serviceTwo = function(){ }; 
exports.serviceThree = function(){ }; 

正如你所期望的,這個模塊的用戶,在其導入,將獲得對exports對象的引用,並通過這一點,他們將獲得在它暴露的所有功能。

//module bar.js 
var foo = require('./foo'); 
foo.serviceOne(); 
foo.serviceTwo(); 
foo.serviceThree(); 

技術2 - 替代默認的出口與另一個對象

通過這一點,你可能懷疑對象是鑑於module.exports只是暴露模塊的公共部分,那麼我們就可以一個對象可能會定義我們自己的對象,然後用我們自己的對象替換默認的對象module.exports。例如:

//module foo.js 
var service = { 
    serviceOne: function(){ }, 
    serviceTwo: function(){ }, 
    serviceThree = function(){ } 
}; 

module.exports = service; 

在最後一個例子中的代碼將表現完全按照前面例子中的代碼,它只是這一次我們已經明確地建立我們的出口對象,而不是使用節點默認提供了一個的。

技術3 - 替代默認的出口對象與構造函數

在到目前爲止,我們一直使用的對象的實例作爲我們的目標暴露的例子。然而,在某些情況下,允許用戶按照自己的意願創建給定類型的多個實例似乎更爲方便。沒有什麼能夠阻止我們用其他類型的對象(比如構造函數)替換module.exports對象。在下面的示例中,我們公開了一個構造函數,用戶可以使用該構造函數創建Foo類型的多個實例。

//module Foo.js 
function Foo(name){ 
    this.name = name; 
} 

Foo.prototype.serviceOne = function(){ }; 
Foo.prototype.serviceTwo = function(){ }; 
Foo.prototype.serviceThree = function(){ }; 

module.exports = Foo; 

而這個模塊的用戶可以簡單地做這樣的事情:

//module bar.js 
var Foo = require('./Foo'); 
var foo = new Foo('Obi-wan'); 
foo.serviceOne(); 
foo.serviceTwo(); 
foo.serviceThree(); 

技術4 - 替代默認的出口對象與普通老式功能

很容易,現在想象如果我們可以使用構造函數,那麼我們也可以使用任何其他普通的舊JavaScript函數作爲module.exports中公開的目標。如以下示例所示,其中導出的函數允許此模塊的用戶訪問其他幾個封裝服務對象之一。

//foo.js 
var serviceA = {}; 
serviceA.serviceOne = function(){ }; 
serviceA.serviceTwo = function(){ }; 
serviceA.serviceThree = function(){ }; 

var serviceB = {}; 
serviceB.serviceOne = function(){ }; 
serviceB.serviceTwo = function(){ }; 
serviceB.serviceThree = function(){ }; 

module.exports = function(name){ 
    switch(name){ 
     case 'A': return serviceA; 
     case 'B': return serviceB; 
     default: throw new Error('Unknown service name: ' + name); 
    } 
}; 

現在導入這個模塊的用戶接收到我們的上述聲明匿名函數的引用,然後她就可以簡單地調用來訪問我們的封裝對象的一個​​功能。例如:

//module bar.js 
var foo = require('./foo'); 
var obj = foo('A'); 
obj.serviceOne(); 
obj.serviceTwo(); 
obj.serviceThree(); 

許多程序員通常會調用立即由require返回的函數,而不是先將它指定給引用。例如:

//module bar.js 
var foo = require('./foo')('A'); 
foo.serviceOne(); 
foo.serviceTwo(); 
foo.serviceThree(); 

因此,簡言之,它如下很簡單:我們在module.exports揭露一切都是我們所得到的,當我們調用require。使用不同的技術,我們可以暴露對象,構造函數,屬性等。

基於所有這些例子,我說在代碼中使用模塊模式對我來說沒有意義。

使用模塊模式和Node.js的模塊

但是,如果你將創建你想在這兩個的Node.js和在瀏覽器中使用一個庫,然後使用兩個模式可以使感。雖然這在你的問題中並不明顯。但是,如果是這樣的話,那麼你可以把這兩個想法結合在一起。

舉例來說,做這樣的事情:

var TestModule; 

(function (TestModule) { 

    var counter = 0; 
    TestModule.incrementCounter = function(){ 
     return counter++; 
    }; 
    TestModule.resetCounter = function(){ 
     console.log('Last Counter Value before RESET :' + counter); 
     counter = 0; 
    }; 

    return TestModule; 

})(typeof module === 'undefined' 
    ? (TestModule || (TestModule = {})) 
    : module.exports); 

當Node.js的運行,那麼內IIFETestModule對應module.exports對象,在瀏覽器中運行時,該TestModule代表一個命名空間。

所以,如果你是在節點之間運行,你可以這樣做:

var testModule = require('./testModule'); 
testModule.incrementCounter(); 

如果你是在瀏覽器中運行,然後加載此腳本後,就可以直接訪問該命名空間TestModule。

TestModule.incrementCounter(); 
+1

**謝謝**你解決了我所有的疑惑!使用這兩種模式這是一個技巧,我會用很多! – cicciosgamino