摘要:誠然,主要服務(wù)于模塊和包,由于簡(jiǎn)單的模塊化語法和可復(fù)用性,大量和瀏覽器的包出現(xiàn)在上,也成為世界上最大的包管理器。規(guī)范中包含了一個(gè)原生的模塊化系統(tǒng),一般稱之為。
對(duì)于 JavaScript 來說,模塊化是一個(gè)相對(duì)現(xiàn)代的概念,這篇文章會(huì)帶你在 JavaScript 的世界里快速瀏覽模塊化的歷史進(jìn)程~
Script 標(biāo)簽和閉包在早些年間,JavaScript 就是直接寫在 HTML 的 標(biāo)簽里的,最多也就是放在獨(dú)立的文件里面,而它們也都共享一個(gè)全局作用域。
任何 JS 文件里面聲明的變量都會(huì)被附加在全局的 window 對(duì)象上,并且還有可能意外覆蓋掉第三方庫中的變量。
隨著 web 應(yīng)用越來越復(fù)雜,共享全局作用域這種方式的弊端開始顯現(xiàn),于是 IIFE(立即調(diào)用函數(shù)表達(dá)式)就被發(fā)明了出來,并且廣為使用。IIFE 就是將一整段代碼包裹在一個(gè)函數(shù)中,然后立即執(zhí)行這個(gè)函數(shù)。在 JavaScript 中,每個(gè)函數(shù)都有一個(gè)作用域,所以在函數(shù)中聲明的變量就只在這個(gè)函數(shù)中可見。即使有變量提升,變量也不會(huì)污染到全局作用域中。
下面讓我們看幾個(gè) IIFE 的寫法,每個(gè) IIFE 的作用域都是獨(dú)立的,其中第一種寫法比較常見:
(function() { console.log("IIFE using parenthesis") })() ~function() { console.log("IIFE using a bitwise operator") }() void function() { console.log("IIFE using the void operator") }()
使用 IIFE 這種方式,某個(gè)庫如果想要暴露全局變量,可以在 window 上綁定一個(gè)對(duì)象作為命名空間,這樣就避免了污染全局作用域。看下面的代碼,假如我們要建立一個(gè) mathlib 工具,它有一個(gè) sum 方法。假如這個(gè)工具有多個(gè)模塊,也可以建立多個(gè)文件,每個(gè)文件里都是一個(gè) IIFE,然后向 window.mathlib 對(duì)象中添加方法就可以了:
(function() { window.mathlib = window.mathlib || {} window.mathlib.sum = sum function sum(...values) { return values.reduce((a, b) => a + b, 0) } })() mathlib.sum(1, 2, 3) // <- 6
IIFE 這種方式可以說是模塊化的先河,它讓開發(fā)者可以將模塊放在多帶帶的文件中,并且不污染全局作用域。
當(dāng)然 IIFE 也有缺點(diǎn),它并沒有一個(gè)明確的依賴樹,這使得開發(fā)者只能自己確保 JS 文件的加載順序。
RequireJS, AngularJS 和依賴注入RequireJS 和 AngularJS 的出現(xiàn),讓我們知道了依賴注入是什么,即需要用哪個(gè)模塊,就注入哪個(gè)模塊。
下面的例子我們先用 RequireJS 的 define 方法定義一個(gè)沒有依賴的 mathlib/sum.js 模塊:
define(function() { return sum function sum(...values) { return values.reduce((a, b) => a + b, 0) } })
然后我們可以創(chuàng)建一個(gè)入口模塊 mathlib.js 用來集合所有子模塊。我們的例子中只有 mathlib/sum 一個(gè)子模塊,但是你可以在 mathlib 文件夾中隨意擴(kuò)展。下面我們聲明 mathlib 模塊的依賴,并將依賴作為形參按順序傳入工廠方法,并返回 mathlib 模塊對(duì)象:
define(["mathlib/sum"], function(sum) { return { sum } })
好了我們已經(jīng)定義了一個(gè) mathlib 庫,下面就可以用 require 引入并使用它:
require(["mathlib"], function(mathlib) { mathlib.sum(1, 2, 3) // <- 6 })
RequireJS 在內(nèi)部維護(hù)了一個(gè)依賴樹,讓開發(fā)者不用關(guān)心依賴之間的順序,只需要在需要的地方聲明要加載的模塊即可使用。
這種明確地聲明依賴的寫法讓各個(gè)模塊間的依賴都非常清晰,并且反過來促進(jìn)了模塊化的發(fā)展。
但是 RequireJS 并不是沒有缺點(diǎn)。它的整個(gè)模式專注于解決異步加載模塊,卻忽略了在生產(chǎn)環(huán)境下,異步加載多個(gè)模塊造成的網(wǎng)絡(luò)請(qǐng)求過多等性能影響。如果依賴過多,開發(fā)者也將面臨一個(gè)很長(zhǎng)的依賴數(shù)組和回調(diào)里面的形參列表。同時(shí)它的 API 也不夠直觀,就拿聲明一個(gè)含有依賴的模塊來說,就有很多種不同的寫法。
AngularJS 的依賴注入系統(tǒng)也面臨同樣的問題。有一個(gè)方法可以根據(jù)形參名字來解析模塊,讓開發(fā)者不用再寫那個(gè)依賴數(shù)組,但是卻對(duì)代碼壓縮工具不友好,因?yàn)閴嚎s后變量名就變短了,也就找不到相應(yīng)的依賴。
直到 AngularJS v1 之后,可以通過一種構(gòu)建任務(wù),將以下代碼:
module.factory("calculator", function(mathlib) { // … })
轉(zhuǎn)換成可壓縮的帶依賴數(shù)組的代碼:
module.factory("calculator", ["mathlib", function(mathlib) { // … }])
然鵝不得不提的是,用工程師思維添加了這么一個(gè)構(gòu)建步驟,解決了這個(gè)本不應(yīng)該出現(xiàn)的問題,但是這本身性價(jià)比實(shí)在是不高,于是大部分開發(fā)者還是選擇自己手寫所有的依賴數(shù)組(我當(dāng)年就是這樣,哈哈)。
Node.js 和 CommonJSCommonJS 模塊系統(tǒng)是 Node.js 中眾多革新的一個(gè),也叫 CJS。得力于 Node.js 可以直接訪問文件系統(tǒng),CommonJS 規(guī)范更貼近的是傳統(tǒng)的模塊加載方式。在 CommonJS 中,每個(gè)文件都是一個(gè)模塊,并具有自己獨(dú)立的作用域。依賴的加載使用一個(gè)同步的 require 函數(shù),這個(gè)函數(shù)可以在模塊的任意地方調(diào)用:
const mathlib = require("./mathlib")
與 RequireJS 和 AngularJS 相似的是, CommonJS 依賴也是與文件路徑相關(guān)聯(lián)。但是與它們最大的區(qū)別,就是 CommonJS 完全拋棄了包裝函數(shù)和依賴數(shù)組,并且require 函數(shù)可以像 JS 表達(dá)式一樣,在模塊的任何地方使用。
在 RequireJS 和 AngularJS 中,你可能有很多動(dòng)態(tài)定義的模塊,然而 CommonJS 中的文件和模塊是一一對(duì)應(yīng)的。與此同時(shí),RequireJS 眾多的模塊定義方式,與 AngularJS 中的 factory、service、provider 都讓人頭大。與之相反的是,CommonJS 只有一種模塊加載方式,一個(gè) JS 文件就是一個(gè)模塊,加載依賴只需要用 require,導(dǎo)出模塊只需要將要導(dǎo)出的值賦給 module.exports。這些優(yōu)點(diǎn)都讓 CommonJS 模塊系統(tǒng)更簡(jiǎn)潔和易于使用。
終于,Browserify 作為橋梁,打通了 CommonJS 在 Node.js 和瀏覽器端的鴻溝。它可以將眾多模塊打包成一個(gè)可在瀏覽器中運(yùn)行的文件。而 npm 源的出現(xiàn),作為 CommonJS 的殺手級(jí)功能,基本上確立了模塊加載生態(tài)中的事實(shí)標(biāo)準(zhǔn)。
誠然,npm 主要服務(wù)于 CommonJS 模塊和 JavaScript 包,由于簡(jiǎn)單的模塊化語法和可復(fù)用性,大量 Node.js 和 web 瀏覽器的包出現(xiàn)在 npm 上,npm 也成為世界上最大的包管理器。
ES6, import, Babel, 和 WebpackES6 是在 2015 年被標(biāo)準(zhǔn)化,在此之前 Babel 一直承擔(dān)著將 ES6 轉(zhuǎn)換為 ES5 的角色,一場(chǎng)新的革命正在襲來。ES6 規(guī)范中包含了一個(gè)原生的模塊化系統(tǒng),一般稱之為 ECMAScript Modules(ESM)。
ESM 受到 CommonJS 和先烈們的影響,提供了一個(gè)靜態(tài)的聲明式的 API 和一個(gè)基于 Promise 的動(dòng)態(tài)加載的 API:
import mathlib from "./mathlib" import("./mathlib").then(mathlib => { // … })
在 ESM 中,每個(gè)文件同樣是一個(gè)模塊,并且具有自己獨(dú)立的作用域和執(zhí)行環(huán)境。ESM 相對(duì) CJS 來說有一個(gè)重要的優(yōu)點(diǎn):即 ESM 是靜態(tài)加載依賴的。靜態(tài)加載極大地提高了模塊系統(tǒng)的自我檢查能力,使得模塊系統(tǒng)可以基于抽象語法樹(AST)作靜態(tài)分析,同時(shí) ESM 限制了加載語句必須置于模塊頂部,也大大簡(jiǎn)化了語法解析和語法檢查。
在 Node.js v8.5.0 中,ESM 已經(jīng)可以通過一個(gè) flag 開啟。大部分主流的瀏覽器也都可以支持 ESM。
Webpack 作為 Browserify 的繼任者,由于功能強(qiáng)大,基本上坐穩(wěn)了通用模塊打包器老大的位置。像 Babel 支持轉(zhuǎn)換 ES6 那樣,Webpack 很早就支持了 ESM 的 import 和 export 語法以及 import() 動(dòng)態(tài)加載函數(shù)。并且在 ESM 的基礎(chǔ)上,添加了 code-splitting 功能,可以將應(yīng)用程序代碼分割成多個(gè)文件來提升首屏加載體驗(yàn)。
鑒于 ESM 是原生的模塊加載規(guī)范,它一統(tǒng)江湖也指日可待了!
原文鏈接
英文原文鏈接
歡迎關(guān)注我的公眾號(hào):碼力全開(codingonfire)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/105090.html
摘要:簡(jiǎn)介原文鏈接簡(jiǎn)稱是一種輕量級(jí),解釋型的編程語言,其函數(shù)是一等公民。標(biāo)準(zhǔn)的目標(biāo)是讓任何一種程序設(shè)計(jì)語言能操控使用任何一種標(biāo)記語言編寫出的任何一份文檔。核心規(guī)定了如何映射基于的文檔結(jié)構(gòu),以便簡(jiǎn)化對(duì)文檔的任意部分的訪問和操作。 JavaScript 簡(jiǎn)介 原文鏈接 JavaScript ( 簡(jiǎn)稱:JS ) 是一種 輕量級(jí),解釋型 的編程語言,其函數(shù)是一等公民。眾所周知,它是用于網(wǎng)頁開發(fā)的腳...
摘要:當(dāng)我們學(xué)習(xí)的模塊化,就會(huì)發(fā)現(xiàn)它的發(fā)展深受的影響。嚴(yán)格模式在模塊系統(tǒng)中,嚴(yán)格模式是默認(rèn)開啟的。同樣的,模塊內(nèi)部的聲明只在模塊內(nèi)部有效。在中,我們使用導(dǎo)入內(nèi)容在模塊中,我們只需要為導(dǎo)入的綁定起一個(gè)名字我們也可以導(dǎo)入具名導(dǎo)出的內(nèi)容。 ES6 模塊系統(tǒng) 在 ES6 之前,我們已經(jīng)知道了 RequireJS,AngularJS 的依賴注入,以及 CommonJS,具體可以看筆者的上一篇文章《JS...
摘要:文章的第二部分涵蓋了內(nèi)存管理的概念,不久后將發(fā)布。的標(biāo)準(zhǔn)化工作是由國際組織負(fù)責(zé)的,相關(guān)規(guī)范被稱為或者。隨著分析器和編譯器不斷地更改字節(jié)碼,的執(zhí)行性能逐漸提高。 原文地址:How Does JavaScript Really Work? (Part 1) 原文作者:Priyesh Patel 譯者:Chor showImg(https://segmentfault.com/img...
摘要:即將立秋的課多周刊第期我們的微信公眾號(hào),更多精彩內(nèi)容皆在微信公眾號(hào),歡迎關(guān)注。若有幫助,請(qǐng)把課多周刊推薦給你的朋友,你的支持是我們最大的動(dòng)力。課多周刊機(jī)器人運(yùn)營中心是如何玩轉(zhuǎn)起來的分享課多周刊是如何運(yùn)營并堅(jiān)持下來的。 即將立秋的《課多周刊》(第2期) 我們的微信公眾號(hào):fed-talk,更多精彩內(nèi)容皆在微信公眾號(hào),歡迎關(guān)注。 若有幫助,請(qǐng)把 課多周刊 推薦給你的朋友,你的支持是我們最大...
閱讀 2267·2021-11-25 09:43
閱讀 3138·2021-10-14 09:42
閱讀 3492·2021-10-12 10:12
閱讀 1578·2021-09-07 10:17
閱讀 1910·2019-08-30 15:54
閱讀 3193·2019-08-30 15:54
閱讀 1568·2019-08-30 15:53
閱讀 1926·2019-08-29 11:21