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