在 Node.js 程式設計中,模組是獨立的功能單元,可以在專案間共用和重用。作為開發人員,模組讓我們的生活更輕鬆,因為我們可以使用模組來增強應用程式的功能,而無需親自編寫。它們還允許我們組織和解耦程式碼,從而使應用程式更易於理解、偵錯和維護。
在這篇文章中,我將介紹如何在 Node.js 中使用模組,重點是如何匯出和消費它們。
由於 JavaScript 最初沒有模組的概念,因此隨著時間的推移,出現了各種相互競爭的格式。下面列出了需要注意的主要格式:
define
函數來定義模組。require
和module.exports
來定義依賴和模組。npm 生態系統就是基於這種格式構建的。ES Module (ESM)
格式。從 ES6(ES2015)開始,JavaScript 支援原生模組格式。它使用 export
關鍵字彙出模組的公共 API,使用 import
關鍵字彙入模組。請注意,本文僅涉及 Node.js 的標準 CommonJS
格式。
Node.js帶來了一系列內建模組,這樣我們就可以直接在程式碼中使用而不需要安裝它們。要使用它們,我們需要使用require
關鍵字引入模組,並賦值給變數。然後就可以用它來呼叫模組公開的任何方法。
舉個例子,要羅列出目錄下的內容,可以使用檔案系統模組,以及該模組的readdir
方法:
const fs = require('fs');
const folderPath = '/home/jim/Desktop/';
fs.readdir(folderPath, (err, files) => {
files.forEach(file => {
console.log(file);
});
});
請注意,在 CommonJS 中,模組是同步載入的,並按照模組出現的順序進行處理。
現在,讓我們看看如何建立自己的模組並匯出它。建立user.js
檔案並新增下列程式碼:
const getName = () => {
return 'Jim';
};
exports.getName = getName;
然後在同一資料夾下建立index.js
,並新增下列程式碼:
const user = require('./user');
console.log(`User: ${user.getName()}`);
使用node index.js
執行程式碼,你會在終端上看到下列輸出:
User: Jim
發生了啥?好吧,如果你檢視user.js
檔案,你會注意到我們定義了一個getName
函數,然後使用exports
關鍵字讓它在任意匯入的地方可用。在index.js
中,我們匯入了該函數並執行了它。還需要注意require
語句,該模型名稱有著./
字首,意味著它是本地檔案。還要注意的是,此處不需要新增副檔名。
我們可以用同樣的方式匯出多個方法和值:
const getName = () => {
return 'Jim';
};
const getLocation = () => {
return 'Munich';
};
const dateOfBirth = '12.01.1982';
exports.getName = getName;
exports.getLocation = getLocation;
exports.dob = dateOfBirth;
在index.js
中這麼使用:
const user = require('./user');
console.log(
`${user.getName()} lives in ${user.getLocation()} and was born on ${user.dob}.`
);
上述程式碼的產出是:
Jim lives in Munich and was born on 12.01.1982.
注意我們給匯出的 dateOfBirth
變數起的名字可以是任何我們喜歡的名字(本例中為 dob
)。它不必與原始變數名相同。
我還應該提到,可以在匯出過程中匯出方法和值,而不僅僅是在檔案末尾匯出。
舉個例子:
exports.getName = () => {
return 'Jim';
};
exports.getLocation = () => {
return 'Munich';
};
exports.dob = '12.01.1982';
多虧了解構賦值,我們可以挑選想要匯入的方法:
const { getName, dob } = require('./user');
console.log(
`${getName()} was born on ${dob}.`
);
上面的範例中,我們單獨匯出了函數和值。這對於整個應用程式都可能需要的輔助函數來說非常方便,但當你有一個只匯出一樣東西的模組時,使用 module.exports
會更常見:
class User {
constructor(name, age, email) {
this.name = name;
this.age = age;
this.email = email;
}
getUserStats() {
return `
Name: ${this.name}
Age: ${this.age}
Email: ${this.email}
`;
}
}
module.exports = User;
在index.js
中:
const User = require('./user');
const jim = new User('Jim', 37, '[email protected]');
console.log(jim.getUserStats());
程式碼輸出如下:
Name: Jim
Age: 37
Email: [email protected]
在開源世界裡,你可以會遇到下列語法:
module.exports = {
getName: () => {
return 'Jim';
},
getLocation: () => {
return 'Munich';
},
dob: '12.01.1982',
};
在這裡,我們將想要匯出的函數和值分配給 module
上的 exports
屬性,當然,這樣做效果很好:
const { getName, dob } = require('./user');
console.log(
`${getName()} was born on ${dob}.`
);
那麼,module.exports
和exports
的不同之處是什麼?一個只是另一個的別名嗎?
有點,但不完全是……
為了闡明我的意思,我們更改index.js
中的程式碼,列印module
的值:
console.log(module);
輸出如下:
Module {
id: '.',
exports: {},
parent: null,
filename: '/home/jim/Desktop/index.js',
loaded: false,
children: [],
paths:
[ '/home/jim/Desktop/node_modules',
'/home/jim/node_modules',
'/home/node_modules',
'/node_modules' ] }
正如你看到的,module
有一個exports
屬性。在exports
上新增一些東西:
// index.js
exports.foo = 'foo';
console.log(module);
輸出如下:
Module {
id: '.',
exports: { foo: 'foo' },
...
為 exports
分配的屬性也會將它們新增到 module.exports
。這是因為(至少最初)exports
是對 module.exports
的參照。
由於 module.exports
和 exports
都指向同一個物件,因此使用哪個通常並不重要。例如:
exports.foo = 'foo';
module.exports.bar = 'bar';
這段程式碼將導致模組的匯出物件為 { foo: 'foo', bar: 'bar' }
。
不過,有一個注意事項。無論你將什麼賦值給 module.exports
,都將從你的模組中匯出什麼。
那麼,請看下面的內容:
exports.foo = 'foo';
module.exports = () => { console.log('bar'); };
這樣只會匯出一個匿名函數。foo
變數將被忽略。
模組已成為 JavaScript 生態系統不可或缺的一部分,它使我們能夠將較小的部分組成大型程式。我希望本文能為你介紹如何在 Node.js 中使用模組,並幫助你揭開模組語法的神祕面紗。
以上就是本文的全部內容,如果對你有所幫助,歡迎點贊、收藏、轉發~