官术网_书友最值得收藏!

3.4 Node.js的模塊系統(tǒng)

Node.js應(yīng)用由模塊組成,采用CommonJS模塊規(guī)范。

每個JS文件就是一個模塊,有獨(dú)立的作用域。在一個文件中定義的變量、函數(shù)、類在其他文件都不可見。

// example.js
function sum(a, b) {
  return a + b;
}

上述代碼中sum函數(shù)只有example.js中能調(diào)用,其他文件則不可以調(diào)用。

3.4.1 module和exports

1.基本用法

CommonJS規(guī)范規(guī)定,每個模塊內(nèi)部的變量module代表當(dāng)前模塊。

module是一個對象,module.exports是對外的接口。加載模塊實(shí)際上是讀取該模塊的module.exports屬性。

module.exports也是一個對象,所有需要導(dǎo)出的變量、函數(shù)、類都需要掛載到該對象上才能實(shí)現(xiàn)導(dǎo)出。

// example.js
function sum(a, b) {
  return a + b;
}

module.exports.sum = sum;

為了方便起見,Node.js為每個模塊提供了一個exports變量,在同一個模塊中,module.exports和exports是恒等的(類型和值都相等)。因此在實(shí)際開發(fā)中,建議通過exports.xxx的形式導(dǎo)出變量、函數(shù)、類。

不建議更改exports的指向,否則模塊將不能正常導(dǎo)出。

下列代碼無法導(dǎo)出sum函數(shù),因為exports由于重新賦值導(dǎo)致指向被更改。

// example.js
exports.sum = function(a, b) {
  return a + b;
}
exports = 'Hello World';

如果模塊只需要導(dǎo)出一個變量、函數(shù)、類,只能對module.exports進(jìn)行賦值,對exports進(jìn)行賦值達(dá)不到如期作用。

上面講到module.exports是恒等于exports的,為什么對exports進(jìn)行賦值達(dá)不到如期作用呢?

// a.js
exports = 'hello world';
// b.js
module.exports = 'hello world';
// c.js
const hello = require('./a');
console.log(hello); // {}

const hello2 = require('./b');

console.log(hello2); // hello world
2.原理解讀

exports只是一個別名,類似于下面的代碼:

         var exports = module.exports;

當(dāng)不對exports重新賦值時,exports指向不變,exports.xxx也會如期地添加到module.exports中。

當(dāng)對exports重新賦值時,exports和module.exports關(guān)聯(lián)就不存在了,修改exports不會對module.exports產(chǎn)生作用。

3.4.2 require

1.基本用法

CommonJS規(guī)定require用于加載模塊文件。

require讀取并執(zhí)行一個JS模塊,然后返回該模塊的exports對象。如果模塊未找到,則會拋出錯誤。

// math.js
exports.sum = function(a, b) {
  return a + b;
}

// index.js
const math = require('./math');
math.sum(1, 1);
2.加載規(guī)則

加載模塊時模塊擴(kuò)展名為.js。也就是說下列代碼是一樣的:

const math = require('./math');
const math2 = require('./math2');

根據(jù)傳入的參數(shù),require會有不同的規(guī)則(以下規(guī)則無先后順序):

(1)如果參數(shù)以'/'開頭,則表示需要加載的是一個絕對路徑的JS文件。如require('/home/xialei/math')將加載/home/xialei/math.js。

(2)如果參數(shù)字符串是以'./'開頭,則表示需要加載一個相對路徑的模塊文件。如require('./math')將加載位于當(dāng)前模塊同目錄下的math.js文件。

(3)如果參數(shù)不以'./'或'/'開頭,則需要加載的是核心模塊或者當(dāng)前工作目錄中node_modules下的模塊。

(4)如果沒有找到指定的模塊文件,Node.js會嘗試自動添加.js、.json、.node(編譯后的二進(jìn)制模塊)后再去搜索。

(5)如果傳入的參數(shù)解析之后是一個目錄,Node.js會自動讀取該目錄下的package.json文件,根據(jù)main字段來加載真正的入口文件。如果該目錄下沒有package.json文件,則嘗試加載index.js或index.node。

3.4.3 開發(fā)一個自定義模塊

我們將開發(fā)一個與時間操作相關(guān)的函數(shù)模塊來鞏固本節(jié)所學(xué),示例代碼如下。

date.js:

index.js:

const date = require('./date');

const now = parseInt(Date.now() / 1000, 10);

console.log(date.formatTime(now - 60));
console.log(date.formatTime(now - 600));
console.log(date.formatTime(now - 5400));
console.log(date.formatTime(now - 3600 * 23));
console.log(date.formatTime(now - 3600 * 24));
console.log(date.formatTime(now - 3600 * 24 * 3));
在終端輸入以下命令執(zhí)行index.js:
node index.js

輸出如下:

剛剛
1小時內(nèi)
3小時內(nèi)
今天
1天前
Fri Oct 23 2019 18:07:45 GMT+0800 (中國標(biāo)準(zhǔn)時間)
主站蜘蛛池模板: 邹城市| 阳高县| 卢龙县| 墨玉县| 南投市| 惠州市| 富顺县| 五华县| 淳化县| 察雅县| 汉沽区| 扎赉特旗| 淮阳县| 阳春市| 汝城县| 垫江县| 威海市| 庆元县| 子洲县| 台前县| 依兰县| 迭部县| 防城港市| 三明市| 阳泉市| 兴仁县| 富阳市| 连南| 贺州市| 浑源县| 丰都县| 体育| 双峰县| 甘泉县| 瓦房店市| 南郑县| 维西| 寿光市| 汉中市| 兴城市| 昌宁县|