摘要:參考資料前端模塊化詳解完整版入門近一萬字的語法知識(shí)點(diǎn)補(bǔ)充徹底搞清楚中的和和詳解
前言
前端的模塊化之路經(jīng)歷了漫長的過程,想詳細(xì)了解的小伙伴可以看浪里行舟大神寫的前端模塊化詳解(完整版),這里根據(jù)幾位大佬們寫的文章,將模塊化規(guī)范部分做了匯總和整理,希望讀完的小伙伴能有些收獲,也希望覺得有用的小伙伴可以點(diǎn)個(gè)贊,筆芯。
什么是模塊將一個(gè)復(fù)雜的程序依據(jù)一定的規(guī)則(規(guī)范)封裝成幾個(gè)塊(文件), 并進(jìn)行組合在一起
塊的內(nèi)部數(shù)據(jù)與實(shí)現(xiàn)是私有的,只是向外部暴露一些接口(方法)與外部其它模塊通信
CommonJSNode 應(yīng)用由模塊組成,采用 CommonJS 模塊規(guī)范。每個(gè)文件就是一個(gè)模塊,有自己的作用域。在一個(gè)文件里面定義的變量、函數(shù)、類,都是私有的,對(duì)其他文件不可見。在服務(wù)器端,模塊的加載是運(yùn)行時(shí)同步加載的;在瀏覽器端,模塊需要提前編譯打包處理。
CommonJS規(guī)范加載模塊是同步的,也就是說,只有加載完成,才能執(zhí)行后面的操作。
基本語法:
暴露模塊:module.exports = value 或 exports.xxx = value
引入模塊:require(xxx),如果是第三方模塊,xxx為模塊名;如果是自定義模塊,xxx為模塊文件路徑
但是,CommonJs有一個(gè)重大的局限使得它不適用于瀏覽器環(huán)境,那就是require操作是同步的。這對(duì)服務(wù)器端不是一個(gè)問題,因?yàn)樗械哪K都存放在本地硬盤,可以同步加載完成,等待時(shí)間就是硬盤的讀取時(shí)間。但是,對(duì)于瀏覽器,這卻是一個(gè)大問題,因?yàn)槟K都放在服務(wù)器端,等待時(shí)間取決于網(wǎng)速的快慢,可能要等很長時(shí)間,瀏覽器處于”假死”狀態(tài)。
因此,瀏覽器端的模塊,不能采用”同步加載”(synchronous),只能采用”異步加載”(asynchronous),這就是AMD規(guī)范誕生的背景。
AMD特點(diǎn):非同步加載模塊,允許指定回調(diào)函數(shù),瀏覽器端一般采用AMD規(guī)范
代表作:require.js
用法:
//定義沒有依賴的模塊 define(function(){ return 模塊 }) //定義有依賴的模塊 define(["module1", "module2"], function(m1, m2){ return 模塊 }) //引入使用模塊 require(["module1", "module2"], function(m1, m2){ //使用m1/m2 })CMD
特點(diǎn):專門用于瀏覽器端,模塊的加載是異步的,模塊使用時(shí)才會(huì)加載執(zhí)行
代表作:Sea.js
用法:
//定義沒有依賴的模塊 define(function(require, exports, module){ exports.xxx = value module.exports = value }) //定義有依賴的模塊 define(function(require, exports, module){ //引入依賴模塊(同步) var module2 = require("./module2") //引入依賴模塊(異步) require.async("./module3", function (m3) { }) //暴露模塊 exports.xxx = value }) //引入使用模塊 define(function (require) { var m1 = require("./module1") var m4 = require("./module4") m1.show() m4.show() })CMD與AMD區(qū)別
AMD和CMD最大的區(qū)別是對(duì)依賴模塊的執(zhí)行時(shí)機(jī)處理不同,而不是加載的時(shí)機(jī)或者方式不同,二者皆為異步加載模塊。
AMD依賴前置,js可以方便知道依賴模塊是誰,立即加載;
而CMD就近依賴,需要使用把模塊變?yōu)樽址馕鲆槐椴胖酪蕾嚵四切┠K,這也是很多人詬病CMD的一點(diǎn),犧牲性能來帶來開發(fā)的便利性,實(shí)際上解析模塊用的時(shí)間短到可以忽略。
一句話總結(jié):
兩者都是異步加載,只是執(zhí)行時(shí)機(jī)不一樣。AMD是依賴前置,提前執(zhí)行,CMD是依賴就近,延遲執(zhí)行。
UMD是AMD和CommonJS的糅合:
AMD模塊以瀏覽器第一的原則發(fā)展,異步加載模塊。
CommonJS模塊以服務(wù)器第一原則發(fā)展,選擇同步加載,它的模塊無需包裝(unwrapped modules)。
這迫使人們又想出另一個(gè)更通用的模式UMD (Universal Module Definition)。希望解決跨平臺(tái)的解決方案。
UMD先判斷是否支持Node.js的模塊(exports)是否存在,存在則使用Node.js模塊模式。
在判斷是否支持AMD(define是否存在),存在則使用AMD方式加載模塊。
(function (window, factory) { if (typeof exports === "object") { module.exports = factory(); } else if (typeof define === "function" && define.amd) { define(factory); } else { window.eventUtil = factory(); } })(this, function () { //module ... });ES6模塊化
ES6 模塊的設(shè)計(jì)思想是盡量的靜態(tài)化,使得編譯時(shí)就能確定模塊的依賴關(guān)系,以及輸入和輸出的變量。CommonJS 和 AMD 模塊,都只能在運(yùn)行時(shí)確定這些東西。比如,CommonJS 模塊就是對(duì)象,輸入時(shí)必須查找對(duì)象屬性。
ES6 Module默認(rèn)目前還沒有被瀏覽器支持,需要使用babel,在日常寫demo的時(shí)候經(jīng)常會(huì)顯示這個(gè)錯(cuò)誤:
ES6模塊使用import關(guān)鍵字導(dǎo)入模塊,export關(guān)鍵字導(dǎo)出模塊:
/** 導(dǎo)出模塊的方式 **/ var a = 0; export { a }; //第一種 export const b = 1; //第二種 let c = 2; export default { c }//第三種 let d = 2; export default { d as e }//第四種,別名 /** 導(dǎo)入模塊的方式 **/ import { a } from "./a.js" //針對(duì)export導(dǎo)出方式,.js后綴可省略 import main from "./c" //針對(duì)export default導(dǎo)出方式,使用時(shí)用 main.c import "lodash" //僅僅執(zhí)行l(wèi)odash模塊,但是不輸入任何值命名式導(dǎo)出與默認(rèn)導(dǎo)出
export {<變量>}這種方式一般稱為 命名式導(dǎo)出 或者 具名導(dǎo)出,導(dǎo)出的是一個(gè)變量的引用。
export default這種方式稱為 默認(rèn)導(dǎo)出 或者 匿名導(dǎo)出,導(dǎo)出的是一個(gè)值。
舉例:
// a.js let x = 10 let y = 20 setTimeout(()=>{ x = 100 y = 200 },100) export { x } export default y // b.js import { x } from "./a.js" import y from "./a.js" setTimeout(()=>{ console.log(x,y) // 100,20 },100)ES6 模塊與 CommonJS 模塊的差異
① CommonJS 模塊輸出的是一個(gè)值的拷貝,ES6 模塊輸出的是值的引用。
CommonJS 模塊輸出的是值的拷貝,也就是說,一旦輸出一個(gè)值,模塊內(nèi)部的變化就影響不到這個(gè)值。而且,CommonJS 模塊無論加載多少次,都只會(huì)在第一次加載時(shí)運(yùn)行一次,以后再加載,返回的都是第一次運(yùn)行結(jié)果的緩存,除非手動(dòng)清除系統(tǒng)緩存。
?ES6 模塊的運(yùn)行機(jī)制與 CommonJS 不一樣,JS 引擎對(duì)腳本靜態(tài)分析的時(shí)候,遇到模塊加載命令import,就會(huì)生成一個(gè)只讀引用,等到腳本真正執(zhí)行時(shí),再根據(jù)這個(gè)只讀引用,到被加載的那個(gè)模塊里面去取值。換句話說,ES6 的import有點(diǎn)像 Unix 系統(tǒng)的“符號(hào)連接”,原始值變了,import加載的值也會(huì)跟著變。因此,ES6 模塊是動(dòng)態(tài)引用,并且不會(huì)緩存值,模塊里面的變量綁定其所在的模塊。
② CommonJS 模塊是運(yùn)行時(shí)加載,ES6 模塊是編譯時(shí)輸出接口。
CommonJS 加載的是一個(gè)對(duì)象(即module.exports屬性),該對(duì)象只有在腳本運(yùn)行完才會(huì)生成。即在輸入時(shí)是先加載整個(gè)模塊,生成一個(gè)對(duì)象,然后再從這個(gè)對(duì)象上面讀取方法,這種加載稱為“運(yùn)行時(shí)加載”。
例如:
// CommonJS模塊 let { stat, exists, readFile } = require("fs"); // 等同于 let _fs = require("fs"); let stat = _fs.stat; let exists = _fs.exists; let readfile = _fs.readfile;
上面代碼的實(shí)質(zhì)是整體加載fs模塊(即加載fs的所有方法),生成一個(gè)對(duì)象(_fs),然后再從這個(gè)對(duì)象上面讀取 3 個(gè)方法。因?yàn)橹挥羞\(yùn)行時(shí)才能得到這個(gè)對(duì)象,導(dǎo)致完全沒辦法在編譯時(shí)做“靜態(tài)優(yōu)化”。
ES6 模塊不是對(duì)象,它的對(duì)外接口只是一種靜態(tài)定義,在代碼靜態(tài)解析階段就會(huì)生成。通過export命令顯式指定輸出的代碼,import時(shí)采用靜態(tài)命令的形式。即在import時(shí)可以指定加載某個(gè)輸出值,而不是加載整個(gè)模塊,這種加載稱為“編譯時(shí)加載”或者“靜態(tài)加載”。
// ES6模塊 import { stat, exists, readFile } from "fs";
上面代碼的實(shí)質(zhì)是從fs模塊加載 3 個(gè)方法,其他方法不加載。即 ES6 可以在編譯時(shí)就完成模塊加載,效率要比 CommonJS 模塊的加載方式高。當(dāng)然,這也導(dǎo)致了沒法引用 ES6 模塊本身,因?yàn)樗?strong>不是對(duì)象。
由于 ES6 模塊是編譯時(shí)加載,使得靜態(tài)分析成為可能。有了它,就能進(jìn)一步拓寬 JavaScript 的語法,比如引入宏(macro)和類型檢驗(yàn)(type system)這些只能靠靜態(tài)分析實(shí)現(xiàn)的功能。
除了靜態(tài)加載帶來的各種好處,ES6 模塊還有以下好處:
不再需要UMD模塊格式了,將來服務(wù)器和瀏覽器都會(huì)支持 ES6 模塊格式。目前,通過各種工具庫,其實(shí)已經(jīng)做到了這一點(diǎn)。
將來瀏覽器的新API 就能用模塊格式提供,不再必須做成全局變量或者navigator對(duì)象的屬性。
不再需要對(duì)象作為命名空間(比如Math對(duì)象),未來這些功能可以通過模塊提供。
總結(jié)CommonJS規(guī)范主要用于服務(wù)端編程,加載模塊是同步的,這并不適合在瀏覽器環(huán)境,因?yàn)橥揭馕吨枞虞d,瀏覽器資源是異步加載的,因此有了AMD、CMD解決方案。
AMD規(guī)范在瀏覽器環(huán)境中異步加載模塊,而且可以并行加載多個(gè)模塊。不過,AMD規(guī)范開發(fā)成本高,代碼的閱讀和書寫比較困難,模塊定義方式的語義不順暢。
CMD規(guī)范與AMD規(guī)范很相似,都用于瀏覽器編程,依賴就近,延遲執(zhí)行,可以很容易在Node.js中運(yùn)行。不過,依賴SPM打包,模塊的加載邏輯偏重。
ES6 在語言標(biāo)準(zhǔn)的層面上,實(shí)現(xiàn)了模塊功能,而且實(shí)現(xiàn)得相當(dāng)簡單,完全可以取代 CommonJS 和 AMD 規(guī)范,成為瀏覽器和服務(wù)器通用的模塊解決方案。
以上是本篇文章的內(nèi)容,歡迎大家提出自己的想法,我們一起學(xué)習(xí)進(jìn)步,與君共勉。
參考資料前端模塊化詳解(完整版)
ECMAScript 6 入門
近一萬字的ES6語法知識(shí)點(diǎn)補(bǔ)充
徹底搞清楚javascript中的require、import和export
CommonJS,AMD,CMD,ES6,require 和 import 詳解
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/103893.html
摘要:語料庫是由文本構(gòu)成的數(shù)據(jù)集通過提供現(xiàn)成的文本數(shù)據(jù)來輔助文本處理。那么可以用來做什么呢我自己是一名從事是不錯(cuò)的入門選項(xiàng)。大數(shù)據(jù)和人工智能是機(jī)器學(xué)習(xí)和的主要開發(fā)語言。 Python培訓(xùn)有哪些內(nèi)容?很多零基礎(chǔ)學(xué)員不知道Python軟件是干什么用的?Python軟件是Python工程師編寫代碼時(shí)所需...
摘要:的屬性在瀏覽器的控制臺(tái)中,可以直接輸入來查看。可以在瀏覽器的控制臺(tái)中看出哪些是類型的,下帶綠色對(duì)勾的即是,如圖只要是類型的在控制臺(tái)通過是獲取不到的,也不能進(jìn)行修改。當(dāng)會(huì)話過期或被放棄后,服務(wù)器將終止該會(huì)話。在中,用取代了。 本文由云+社區(qū)發(fā)表 在前端面試中,有一個(gè)必問的問題:請(qǐng)你談?wù)刢ookie和localStorage有什么區(qū)別啊? localStorage是H5中的一種瀏覽器本地存...
摘要:以餃子為例,這時(shí)候需要準(zhǔn)備好面粉,剁好的餡料,再調(diào)配好需要的配料,還得等面粉發(fā)酵完畢后和面。包好餃子放進(jìn)蒸屜之中,蒸好后才能享用。與在自己家里面做不同,這里需要一個(gè)餃子的供應(yīng)商,這就是基礎(chǔ)設(shè)施即服務(wù)。在與相關(guān)人士聊云計(jì)算的時(shí)候,有時(shí)會(huì)從他們的最終蹦出諸如IaaS、PaaS和SaaS等相關(guān)名詞,聽的人一頭霧水,而往往與你聊的人,也只能用一些專業(yè)名字來解釋,這樣一來,就更加疑惑了。那么IaaS、...
摘要:因此,年的埃里克施密特首次提出了云計(jì)算的概念,以及后來業(yè)界衍生出來霧計(jì)算霾計(jì)算邊緣計(jì)算等等一系列的計(jì)算方式,接下來,請(qǐng)跟隨小編一起去辨析一下它們到底指的是什么。未來的世界將是一個(gè)萬物互聯(lián)的時(shí)代,隨著物聯(lián)網(wǎng)行業(yè)技術(shù)標(biāo)準(zhǔn)的完善以及關(guān)鍵技術(shù)上的不斷突破,數(shù)據(jù)大爆炸時(shí)代將越走越近。就拿從2016年底開始風(fēng)靡全國甚至是海外市場的共享單車來說吧,據(jù)小編近日從摩數(shù)城市發(fā)布會(huì)獲悉,截止當(dāng)前,僅僅摩拜單車每天...
閱讀 1382·2021-11-22 09:34
閱讀 2587·2021-11-12 10:36
閱讀 1119·2021-11-11 16:55
閱讀 2332·2020-06-22 14:43
閱讀 1474·2019-08-30 15:55
閱讀 1986·2019-08-30 15:53
閱讀 1772·2019-08-30 10:50
閱讀 1230·2019-08-29 12:15