<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 模塊 在計算機程序的開發過程中,隨著程序代碼越寫越多,在一個文件里代碼就會越來越長,越來越不容易維護。 為了編寫可維護的代碼,我們把很多函數分組,分別放到不同的文件里,這樣,每個文件包含的代碼就相對較少,很多編程語言都采用這種組織代碼的方式。在Node環境中,一個.js文件就稱之為一個模塊(module)。 使用模塊有什么好處? 最大的好處是大大提高了代碼的可維護性。其次,編寫代碼不必從零開始。當一個模塊編寫完畢,就可以被其他地方引用。我們在編寫程序的時候,也經常引用其他模塊,包括Node內置的模塊和來自第三方的模塊。 使用模塊還可以避免函數名和變量名沖突。相同名字的函數和變量完全可以分別存在不同的模塊中,因此,我們自己在編寫模塊時,不必考慮名字會與其他模塊沖突。 在上一節,我們編寫了一個`hello.js`文件,這個`hello.js`文件就是一個模塊,模塊的名字就是文件名(去掉`.js`后綴),所以`hello.js`文件就是名為`hello`的模塊。 我們把`hello.js`改造一下,創建一個函數,這樣我們就可以在其他地方調用這個函數: ``` 'use strict'; var s = 'Hello'; function greet(name) { console.log(s + ', ' + name + '!'); } module.exports = greet; ``` 函數`greet()`是我們在`hello`模塊中定義的,你可能注意到最后一行是一個奇怪的賦值語句,它的意思是,把函數`greet`作為模塊的輸出暴露出去,這樣其他模塊就可以使用`greet`函數了。 問題是其他模塊怎么使用`hello`模塊的這個`greet`函數呢?我們再編寫一個`main.js`文件,調用`hello`模塊的`greet`函數: ``` 'use strict'; // 引入hello模塊: var greet = require('./hello'); var s = 'Michael'; greet(s); // Hello, Michael! ``` 注意到引入`hello`模塊用Node提供的`require`函數: ``` var greet = require('./hello'); ``` 引入的模塊作為變量保存在`greet`變量中,那`greet`變量到底是什么東西?其實變量`greet`就是在`hello.js`中我們用`module.exports = greet;`輸出的`greet`函數。所以,`main.js`就成功地引用了`hello.js`模塊中定義的`greet()`函數,接下來就可以直接使用它了。 在使用`require()`引入模塊的時候,請注意模塊的相對路徑。因為`main.js`和`hello.js`位于同一個目錄,所以我們用了當前目錄`.`: ``` var greet = require('./hello'); // 不要忘了寫相對目錄! ``` 如果只寫模塊名: ``` var greet = require('hello'); ``` 則Node會依次在內置模塊、全局模塊和當前模塊下查找`hello.js`,你很可能會得到一個錯誤: ``` module.js throw err; ^ Error: Cannot find module 'hello' at Function.Module._resolveFilename at Function.Module._load ... at Function.Module._load at Function.Module.runMain ``` 遇到這個錯誤,你要檢查: * 模塊名是否寫對了; * 模塊文件是否存在; * 相對路徑是否寫對了。 ## CommonJS規范 這種模塊加載機制被稱為CommonJS規范。在這個規范下,每個`.js`文件都是一個模塊,它們內部各自使用的變量名和函數名都互不沖突,例如,`hello.js`和`main.js`都申明了全局變量`var s = 'xxx'`,但互不影響。 一個模塊想要對外暴露變量(函數也是變量),可以用`module.exports = variable;`,一個模塊要引用其他模塊暴露的變量,用`var ref = require('module_name');`就拿到了引用模塊的變量。 ## 結論 要在模塊中對外輸出變量,用: ``` module.exports = variable; ``` 輸出的變量可以是任意對象、函數、數組等等。 要引入其他模塊輸出的對象,用: ``` var foo = require('other_module'); ``` 引入的對象具體是什么,取決于引入模塊輸出的對象。 ## 深入了解模塊原理 如果你想詳細地了解CommonJS的模塊實現原理,請繼續往下閱讀。如果不想了解,請直接跳到最后做練習。 當我們編寫JavaScript代碼時,我們可以申明全局變量: ``` var s = 'global'; ``` 在瀏覽器中,大量使用全局變量可不好。如果你在`a.js`中使用了全局變量`s`,那么,在`b.js`中也使用全局變量`s`,將造成沖突,`b.js`中對`s`賦值會改變`a.js`的運行邏輯。 也就是說,JavaScript語言本身并沒有一種模塊機制來保證不同模塊可以使用相同的變量名。 那Node.js是如何實現這一點的? 其實要實現“模塊”這個功能,并不需要語法層面的支持。Node.js也并不會增加任何JavaScript語法。實現“模塊”功能的奧妙就在于JavaScript是一種函數式編程語言,它支持閉包。如果我們把一段JavaScript代碼用一個函數包裝起來,這段代碼的所有“全局”變量就變成了函數內部的局部變量。 請注意我們編寫的`hello.js`代碼是這樣的: ``` var s = 'Hello'; var name = 'world'; console.log(s + ' ' + name + '!'); ``` Node.js加載了`hello.js`后,它可以把代碼包裝一下,變成這樣執行: ``` (function () { // 讀取的hello.js代碼: var s = 'Hello'; var name = 'world'; console.log(s + ' ' + name + '!'); // hello.js代碼結束 })(); ``` 這樣一來,原來的全局變量`s`現在變成了匿名函數內部的局部變量。如果Node.js繼續加載其他模塊,這些模塊中定義的“全局”變量`s`也互不干擾。 所以,Node利用JavaScript的函數式編程的特性,輕而易舉地實現了模塊的隔離。 但是,模塊的輸出`module.exports`怎么實現? 這個也很容易實現,Node可以先準備一個對象`module`: ``` // 準備module對象: var module = { id: 'hello', exports: {} }; var load = function (module) { // 讀取的hello.js代碼: function greet(name) { console.log('Hello, ' + name + '!'); } module.exports = greet; // hello.js代碼結束 return module.exports; }; var exported = load(module); // 保存module: save(module, exported); ``` 可見,變量`module`是Node在加載js文件前準備的一個變量,并將其傳入加載函數,我們在`hello.js`中可以直接使用變量`module`原因就在于它實際上是函數的一個參數: ``` module.exports = greet; ``` 通過把參數`module`傳遞給`load()`函數,`hello.js`就順利地把一個變量傳遞給了Node執行環境,Node會把`module`變量保存到某個地方。 由于Node保存了所有導入的`module`,當我們用`require()`獲取module時,Node找到對應的`module`,把這個`module`的`exports`變量返回,這樣,另一個模塊就順利拿到了模塊的輸出: ``` var greet = require('./hello'); ``` 以上是Node實現JavaScript模塊的一個簡單的原理介紹。 ## module.exports vs exports 很多時候,你會看到,在Node環境中,有兩種方法可以在一個模塊中輸出變量: 方法一:對module.exports賦值: ``` // hello.js function hello() { console.log('Hello, world!'); } function greet(name) { console.log('Hello, ' + name + '!'); } function hello() { console.log('Hello, world!'); } module.exports = { hello: hello, greet: greet }; ``` 方法二:直接使用exports: ``` // hello.js function hello() { console.log('Hello, world!'); } function greet(name) { console.log('Hello, ' + name + '!'); } function hello() { console.log('Hello, world!'); } exports.hello = hello; exports.greet = greet; ``` 但是你不可以直接對`exports`賦值: ``` // 代碼可以執行,但是模塊并沒有輸出任何變量: exports = { hello: hello, greet: greet }; ``` 如果你對上面的寫法感到十分困惑,不要著急,我們來分析Node的加載機制: 首先,Node會把整個待加載的`hello.js`文件放入一個包裝函數`load`中執行。在執行這個`load()`函數前,Node準備好了module變量: ``` var module = { id: 'hello', exports: {} }; ``` `load()`函數最終返回`module.exports`: ``` var load = function (exports, module) { // hello.js的文件內容 ... // load函數返回: return module.exports; }; var exported = load(module.exports, module); ``` 也就是說,默認情況下,Node準備的`exports`變量和`module.exports`變量實際上是同一個變量,并且初始化為空對象`{}`,于是,我們可以寫: ``` exports.foo = function () { return 'foo'; }; exports.bar = function () { return 'bar'; }; ``` 也可以寫: ``` module.exports.foo = function () { return 'foo'; }; module.exports.bar = function () { return 'bar'; }; ``` 換句話說,Node默認給你準備了一個空對象`{}`,這樣你可以直接往里面加東西。 但是,如果我們要輸出的是一個函數或數組,那么,只能給`module.exports`賦值: ``` module.exports = function () { return 'foo'; }; ``` 給`exports`賦值是無效的,因為賦值后,`module.exports`仍然是空對象`{}`。 ## 結論 如果要輸出一個鍵值對象`{}`,可以利用`exports`這個已存在的空對象`{}`,并繼續在上面添加新的鍵值; 如果要輸出一個函數或數組,必須直接對`module.exports`對象賦值。 所以我們可以得出結論:直接對`module.exports`賦值,可以應對任何情況: ``` module.exports = { foo: function () { return 'foo'; } }; ``` 或者: ``` module.exports = function () { return 'foo'; }; ``` 最終,我們_強烈建議_使用`module.exports = xxx`的方式來輸出模塊變量,這樣,你只需要記憶一種方法。 ## 練習 編寫`hello.js`,輸出一個或多個函數; 編寫`main.js`,引入`hello`模塊,調用其函數。 ## 參考源碼 [hello.js](https://github.com/michaelliao/learn-javascript/blob/master/samples/node/module/hello.js) [main.js](https://github.com/michaelliao/learn-javascript/blob/master/samples/node/module/main.js)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看