Javascript模塊化

模塊是什么呢?

從Javascript的發(fā)展史來看,模塊系統(tǒng)的出現(xiàn),是一種對(duì)隔絕全局作用域,關(guān)注點(diǎn)分離,顯式依賴定義,高內(nèi)聚、低耦合的結(jié)構(gòu)的追求。

模塊化?

主要解決代碼分割、作用域隔離、模塊之間的依賴管理以及發(fā)布到生產(chǎn)環(huán)境時(shí)的自動(dòng)打包與處理等多個(gè)方面

背景以及問題

在模塊化思維席卷前端之前,早期的代碼或是集中在一個(gè)文件里,或是物理分散在多個(gè)文件里,但對(duì)作用域并無隔離,他們皆可以接觸到全局作用域中的變量,也可以輕而易舉、甚至是在不知情的情況下就將自己的變量與方法暴露到全局中。此外,不同代碼之間依賴關(guān)系不夠明確,關(guān)聯(lián)代碼的執(zhí)行時(shí)機(jī)難以確定, 缺乏分析與加載機(jī)制。

應(yīng)對(duì)

早期為了解決作用域隔離的問題,很多代碼文件會(huì)將代碼包裹在立即執(zhí)行的匿名函數(shù)中,成功將變量和方法定義等局限在自己的函數(shù)作用域里。

(function() {
? ? //....代碼在這里
})();

后期為了解決前端代碼快速膨脹,js文件加載與執(zhí)行難以時(shí)機(jī)的問題,出現(xiàn)了很多模塊依賴加載的規(guī)范:AMD\CMD\COMMONJS\ES MODULE. 模塊的概念開始清晰并統(tǒng)一起來。

個(gè)人認(rèn)為,關(guān)于模塊化規(guī)范的內(nèi)容,主要聚焦在模塊定義,依賴定義,模塊查找,和模塊導(dǎo)出等。

此處需要詳細(xì)了解規(guī)范,作出修改。

COMMONJS規(guī)范

在CommonJS的規(guī)范中,每個(gè)JavaScript文件就是一個(gè)獨(dú)立的模塊上下文,在這個(gè)上下文中創(chuàng)建的屬性和方法都是私有的。它采用同步加載模塊的策略。該方案的關(guān)鍵字是require與module。

Node.js的module實(shí)現(xiàn)

/*** main.js **/

const a = require('./a.js')

console.log(a)

/*** a.js **/

?module.exports = {

? ? blockName: 'module-a'

}

這里定義一個(gè)a模塊。在執(zhí)行模塊之前,node.js會(huì)使用一個(gè)如下的模塊封裝器將其封裝起來,因此可以隔絕全局作用域,而將欲導(dǎo)出的內(nèi)容掛載到傳入的參數(shù)上,就成功暴露相應(yīng)的內(nèi)容給外部。

(function(exports,require,module,__filename,__dirname){? //....模塊A })

在模塊的上下文中,可以訪問到require、exports、module.exports,__filename、__dirname等。

Node.js的模塊加載后會(huì)緩存,模塊定義腳本只會(huì)執(zhí)行一次, 模塊的依賴與元數(shù)據(jù)也是在執(zhí)行時(shí)慢慢補(bǔ)齊。

var router = require('koa-router')()

console.log('測試',module.children[1],module.children[0])?

const mysql = require('./mysql')

console.log('測試2',module.children[1],module.children[0])?

結(jié)果:?

測試 undefined {//.....module1}

測試2 {//.....module2} {//.....module1}

模塊的查找過程

Node.js有核心模塊,文本文件模塊,和目錄模塊。核心模塊是定義在Node.js源碼lib下的二進(jìn)制模塊,會(huì)被優(yōu)先加載。至于文本文件模塊,如果不是以'./', '../','/'開頭,會(huì)進(jìn)入最近的node_module中查找(支持本地化依賴的關(guān)鍵, 第三方模塊);否則 ,應(yīng)該是相對(duì)模塊的路徑進(jìn)行查找。針對(duì)目錄模塊,Node會(huì)讀入目錄下的package.json來嘗試解讀模塊信息,main定義模塊的入口文件,type定義模塊的類型(commonjs or mudule),exports定義導(dǎo)出。關(guān)于模塊類型,有需要注意的是,現(xiàn)在Node.js推出了實(shí)驗(yàn)性特征,可以在較新的版本支持ES MODULE。項(xiàng)目代碼中以.cjs結(jié)尾的文件是commonjs模塊,而以.mjs結(jié)尾是es模塊。但是注意一點(diǎn),es模塊中不可去調(diào)用commonjs模塊,commonjs模塊不可去調(diào)用es模塊。

循環(huán)依賴

? ? /**? ?a.js:? ?*/

?? ? ? console.log('a開始');

?? ? ? exports.done = false;

?? ? ? const b = require('./b.js');

?? ? ? console.log('在a中,b.done = %j',b.done);

?? ? ? exports.done = true;

?? ? ? console.log('a結(jié)束');

??/**? ? b.js: */

?? ? ? console.log('b開始');

?? ? ? exports.done = false;

?? ? ? const a = require('./a.js');

?? ? ? console.log('在b中,a.done = %j',a.done);

?? ? ? exports.done = true;

?? ? ? console.log(‘b結(jié)束');

? /**? ? main.js: */

?? ? ? console.log('main開始');

?? ? ? const a = require('./a.js');

?? ? ? const b = require('./b.js');

?? ? ? console.log('在main中,a.done=%j,b.done=%j',a.done,b.done);

結(jié)果

? ? ? main開始

? ? ? a開始

? ? ? b開始

? ? ? 在b中,a.done = false

? ? ? b結(jié)束

? ? ? 在a中,b.done = true

? ? ? a結(jié)束

? ? ? 在main中,a.done=true,b.done=true

由于在模塊生成代碼執(zhí)行前,模塊的引用便已存在(模塊封裝器傳入),因?yàn)榭梢钥朔h(huán)模塊依賴。

ES MODULE 規(guī)范

ES Module是語法靜態(tài)的,默認(rèn)使用嚴(yán)格模式。import會(huì)自動(dòng)提升到代碼頂層,意味著在編譯時(shí)確定了輸入和導(dǎo)出,可以更加快的查找依賴,可以使用lint工具對(duì)模塊依賴進(jìn)行檢查。

ES 模塊是異步的。你可以認(rèn)為它是異步的因?yàn)閷?shí)際的運(yùn)作被分成了三個(gè)不同的階段 —— 加載,實(shí)例化以及求值,而這些階段都可以分開完成。

深入ES MODULE,請(qǐng)查看

https://www.imooc.com/article/28404?block_id=tuijian_wz

ES MODULE 和COMMONJS 不同

從使用方面來看,ES模塊默認(rèn)嚴(yán)格模式,沒有node_path, 強(qiáng)制文件拓展名,沒有require.main, require, exports, module.exports, __filename, __dirname等,只有import.meta等。

從導(dǎo)出來看,ES MODULE是編譯時(shí)輸出接口,Commonjs是運(yùn)行時(shí)候加載; ES模塊基于活動(dòng)綁定,傳遞只讀引用, 不可改變整體導(dǎo)入對(duì)象(prevent extension & freeze),Commonjs傳遞的緩存值拷貝。Commonjs的導(dǎo)出遵從但同時(shí)也受限于javascript的值賦值與傳遞特性。

var num=1

function add(){

num++

}

module.exports={

num:num, //導(dǎo)出值是值,而不是引用,內(nèi)部的改動(dòng), 不會(huì)影響導(dǎo)出值

add:add

}

//main.js

var mod=require('./module')

console.log(mod.num)//1

mod.add()

console.log(mod.num)//1

//module.js

export var num=1; //導(dǎo)出的是只讀引用,內(nèi)部的值發(fā)生變化會(huì)會(huì)影響[命名導(dǎo)出]

export function add(){ num++;}

//main.js

import {num,add} from './module'

console.log(num);//1

mod.add();

console.log(num);//2?

AMD(CommonJS 瀏覽器端方案)

依賴前置。模塊的依賴需要提前聲明與加載執(zhí)行。

define(['dependencies1','dependencies2'],function(dep1, dep2){/

? ?// dep1 & dep2 已經(jīng)被正確賦值

? ? dep1.func()?

? ?//..... other codes

? ?dep2.func()?

})

CMD(CommonJS 瀏覽器端方案)

依賴就近。模塊的依賴會(huì)被提前加載,但無需提前聲明與執(zhí)行

define(function({

? ?// dependencies1 & dependencies2?已被加載

? ?let dep1 = require('dependencies1')?//依賴此時(shí)執(zhí)行

? ? dep1.func()?

? ?//..... other codes

? let dep2 = require('dependencies2') //依賴此時(shí)執(zhí)行

? ?dep2.func()?

})

UMD

AMD+Commonjs+全局變量三種風(fēng)格的結(jié)合

(function(global,factory){

? ? typeof?exports === 'object' &&?typeof?module !== 'undefined' ? module.exports = factory():

? ? typeof?define === 'function' && define.amd ? define(factory):

? ? (global.libName = factory());

}(this,(function(){ 'use strict';})));

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 01 寫在前面 模塊化簡單來說就是是指把一個(gè)復(fù)雜的系統(tǒng)分解到多個(gè)模塊以方便編碼。JS模塊化的大致流程為:Commo...
    強(qiáng)哥科技興閱讀 463評(píng)論 0 0
  • 什么是模塊化開發(fā)? 前端開發(fā)中,起初只要在script標(biāo)簽中嵌入幾十上百行代碼就能實(shí)現(xiàn)一些基本的交互效果,后來js...
    半世韶華憶闌珊閱讀 722評(píng)論 0 0
  • 參考資料 Modules/1.0——維基百科CommonJS Modules/1.0——伯樂在線js模塊化——博客...
    BeYanJin閱讀 3,251評(píng)論 0 5
  • 參考探索js的模塊化 什么是JavaScript模塊化? 模塊化在我看來,就是把一些公共的函數(shù)封裝起來給其他地方調(diào)...
    海娩閱讀 377評(píng)論 0 2
  • 原文鏈接:http://www.cnblogs.com/lvdabao/p/js-modules-develop....
    舌尖上的大胖閱讀 851評(píng)論 0 1

友情鏈接更多精彩內(nèi)容