CommonJS模塊規(guī)范
- 一個js文件就是一個模塊
- CommonJS 就是一套約定標(biāo)準(zhǔn),不是技術(shù); 用于約定我們的代碼應(yīng)該是怎樣的一種結(jié)構(gòu)。
- Node 采用的模塊化結(jié)構(gòu)是按照 CommonJS 規(guī)范。
- CommonJS的特點(diǎn):
- 所有代碼都運(yùn)行在模塊作用域,不會污染全局作用域。
- 模塊可以多次加載,但是只會在第一次加載時運(yùn)行一次,然后運(yùn)行結(jié)果就被緩存了,以后再加載,就直接讀取緩存結(jié)果。要想讓模塊再次運(yùn)行,必須清除緩存。
- 模塊加載的順序,按照其在代碼中出現(xiàn)的順序。
- 模塊的分類
- 自定義模塊:即我們自己寫的功能模塊文件。
- 核心模塊:即Node自帶的功能模塊,如:HTTP模塊,fs模塊等等。
- 第三方模塊:社區(qū)或第三方開發(fā)好的功能模塊,可以直接拿回來用。
- 模塊的導(dǎo)入
- 通過
require("fs")來加載模塊
- 如果是第三方模塊,需要先使用
npm進(jìn)行下載
- 如果是自定義模塊,需要加上相對路徑./或者../,可以省略.js后綴,如果文件名是index.js那么index.js也可以省略
- 模塊可以被多次加載,但是只會在第一次加載
module.exports與exports
- 載入一個模塊就是構(gòu)建一個 Module 實(shí)例,一個新的 JS 文件就是一個模塊
-
module.exports 是用于為模塊導(dǎo)出成員的接口。
- 在模塊的內(nèi)部,
module變量代表的就是當(dāng)前模塊,它的exports屬性就是對外的接口,加載某個模塊,加載的就是module.exports屬性,這個屬性指向一個空的對象。
-
exports是指向module.exports的引用,相當(dāng)于在模塊開始執(zhí)行的時候進(jìn)行var exports = module.exports操作。從下面的打印中可以看出,它們最初都是一個空對象{},而這兩個對象實(shí)際上指向同一塊內(nèi)存空間,即在不改變它們指向的內(nèi)存地址的前提下,它們是等價的。
console.log(exports) //{}
console.log(module) //Module {……exports: {},parent: null……}
console.log(exports === module.exports) //true
-
require引入的對象本質(zhì)上是module.exports,這也意味著module.exports與exports指向的不是同一塊內(nèi)存時,exports的內(nèi)容就會失效。
//try.js
exports = {name: "Join"}
module.exports = {name: "Bob"}
//main.js
let name = require('./try.js')
console.log(name) //{ name: 'Bob' }
require加載文件規(guī)則
- require('../file.js'); // 上級目錄下找 file.js 文件
require('./file.js'); // 同級目錄找 file.js 文件
require('file.js'); // 同級目錄找 file.js 文件
- 加載順序:
- 按js文件來執(zhí)行(先找對應(yīng)路徑當(dāng)中的module.js文件來加載)
- 按json文件來解析(若上面的js文件找不到時,則找對應(yīng)路徑當(dāng)中的module.json文件來加載)
- 按照預(yù)編譯好的c++模塊來執(zhí)行(尋找對應(yīng)路徑當(dāng)中的module.node文件來加載)
- 若參數(shù)字符串為一個目錄(文件夾)的路徑,則自動先查找該文件夾下的package.json文件,然后再再加載該文件當(dāng)中main字段所指定的入口文件。(若package.json文件當(dāng)中沒有main字段,或者根本沒有package.json文件,則再默認(rèn)查找該文件夾下的index.js文件作為模塊來載入。)
CommonJS引入與ES6的區(qū)別
- CommonJS是直接做一個值的拷貝操作,也就是一旦輸出一個值,模塊內(nèi)部的變化是影響不到這個值的
//try.js
let counter = 1
let addCounter = () => {
counter++
}
module.exports = {
counter,
addCounter
}
//main.js
let func = require('./try.js')
console.log(func.counter) //1
func.addCounter()
console.log(func.counter) //1
- ES6模塊是動態(tài)引用,并且不會緩存值,模塊里面的變量綁定其所在的模塊。
//try.js
export let counter = 1
export let addCounter = () => {
counter++
}
//main.js
import {counter,addCounter} from './try.js'
console.log(counter) //1
addCounter()
console.log(counter) //2
- CommonJS模塊的循環(huán)引用
- 執(zhí)行
node main.js->第一行,require(a.js)
- 進(jìn)入
require(a)方法:判斷緩存->無->初始化一個module->將module加入緩存->執(zhí)行a.js內(nèi)容
- 第一行導(dǎo)出
a=1->第二行引入b.js
- 執(zhí)行b.js的內(nèi)容,第一行導(dǎo)出
b=11,第二行require(a.js)
- 此時a.js是第二次調(diào)用require,判斷緩存->有->繼續(xù)執(zhí)行b.js->第三行打印
1->第四行修改b=22
- b文件執(zhí)行完畢回到a.js中->第三行打印
b=22->導(dǎo)出a=2
- a文件執(zhí)行完畢,回到main.js中->獲取a,第二行輸出
a=2->執(zhí)行完畢
// a.js
module.exports.a = 1;
var b = require('./b');
console.log(b);
module.exports.a = 2;
// b.js
module.exports.b = 11;
var a = require('./a');
console.log(a);
module.exports.b = 22;
//main.js
var a = require('./a');
console.log(a);
Node加載
- Node 要求使用 ES6 模塊需要采用
.mjs后綴文件名。也就是說,Node 遇到.mjs文件,就認(rèn)為它是ES6 模塊,默認(rèn)啟用嚴(yán)格模式,不必在每個模塊文件頂部指定"use strict"。
- 如果不希望將后綴名改成
.mjs,可以在項(xiàng)目的package.json文件中,指定type字段為module。一旦設(shè)置了以后,該目錄里面的 JS 腳本,就被解釋用 ES6 Module。如果這時還要使用 CommonJS 模塊,那么需要將 CommonJS 模塊腳本的后綴名都改成.cjs。如果沒有type字段,或者type字段為commonjs,則.js腳本會被解釋成 CommonJS 模塊。
{
"type": "module" // 開啟 ES6 Module 模式
}
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。