為什么前端越來越難學?聊聊 JavaScript 框架的發展簡史
最近,在網絡看到一張圖片,對比了 2016 年 和 2024 年前端開發所需掌握的技術。
當年只需要知道 HTML、CSS、JavaScript,以及一些 jQuery 的知識,就可以在前端開發的世界中游刃有余。
而如今,我們面對的是 React、Vue、TypeScript、Node.js、Next.js、 shadcn/ui 等各種框架和工具的洪流。
學習成本直線上升,這其中到底發生了什么?
今天我們就從這個問題開始,聊聊 JavaScript 框架的發展過程,了解背后的故事。
前端開發 2016
前端開發 2024
1.JavaScript:一種編程語言的誕生
在講述 JavaScript 框架的發展之前,先簡要回顧一下 JavaScript 的歷史,幫助理解為什么現代前端開發如此混亂。
網景通信公司是一家美國技術公司,開發了第一個廣泛使用的網絡瀏覽器——網景導航器(Netscape Navigator)。
1995 年,網景聘請了 Brendan Eich,希望將 Schem e編程語言集成到其網景導航器中。
然而,Eich 在加入公司僅 10 天后就創造了一種新的編程語言,起初命名為 Mocha,后改為 LiveScript,最終確定為 JavaScript。
盡管名稱暗示了與 Java 的關聯,JavaScript 實際上與 Java 編程語言關系不大。這一命名更多是出于市場營銷策略,因為當時 Java 正變得越來越受歡迎。
到了 1990 年代末,網景試圖通過 Ecma International 來標準化 JavaScript,這一努力最終導致了 ECMAScript 標準的誕生。
盡管 JavaScript 的發展歷程中有過不少波折,如與微軟的瀏覽器大戰,但它經受住了時間的考驗,成為了世界上最流行的編程語言之一。
1999 年,網景被美國在線(AOL)收購,該產品于 2008 年停止更新和支持。
2.瀏覽器大戰
為了理解現代前端開發背后的混亂,我們需要回到 90 年代中期到 2000 年代初。
那時候,關于瀏覽器的選擇并不多。你要么使用網景/火狐,要么使用微軟的 IE,前者在市場上占有絕大多數份額,高達90%。
Safari 和 macOS(最初稱為Mac OS X)當時幾乎被開發者忽視,我記得 Safari 在 2000 年代初的市場份額不超過 0.5%。
在蓋茨的領導下,微軟展現出了極強的競爭性,簡單地說就是消滅了所有競爭對手。
對微軟來說,瀏覽器與其他商業產品無異,用戶必須購買這些應用程序并將其安裝在個人電腦上。
微軟想要獨占所有市場份額,因此他們的做法很簡單:將 IE 作為默認瀏覽器與 Windows 一同發布,這樣當用戶“打開互聯網”時,映入眼簾的便是 IE。
作為回應,網景嘗試將他們的瀏覽器與 ISP 提供的軟件捆綁。然而,作為市場巨頭的微軟則要求所有第三方應用必須捆綁 IE,將其作為“Windows 上進行網絡訪問的必需組件”。
微軟在處理 IE 中的腳本語言時無視任何標準,完全按照自己的方式行事,不在乎 Web 標準。
接著,微軟對 IE 中的腳本語言為所欲為,無視其他供應商試圖制定的任何標準。在微軟看來,非我族類,其心必異。
如果按照微軟的方式,我們今天可能都在使用 IE 和 VBScript(盡管我認為 VBScript 在當時是一種比 JavaScript 更有能力的腳本語言)。
他們甚至還逆向工程了網景的腳本語言 JavaScript,并將其命名為 JScript。
最終,微軟因壟斷網絡瀏覽器市場而被判有罪,裁定操作系統和瀏覽器必須分離,用戶應有權選擇使用任何他們想要的瀏覽器。
在 VBScript、JScript 和 JavaScript 之間,最終勝出的是 JavaScript,因為開發者可以使用同一種腳本語言為多個瀏覽器進行開發。
但曾有一段時間,網頁代碼中 JavaScript 和 VBScript 混用,造成了巨大的混亂。
注:還存在許多其他腳本語言,如 PerlScript 或 ASP。這與今天 WebAssembly 試圖解決的問題類似,即允許開發者在客戶端使用任何編程語言,同時確保性能和跨瀏覽器的兼容性。
3.jQuery 的誕生
在 2000 年初,Web 世界還像是一個亂世,存在許多相互競爭的標準,廠商們還在摸索如何有效地為Web編程。
如果將今天的前端開發描述為復雜,那么那時它更是混亂無章,尋求幫助的在線教程寥寥無幾。
正是在這種背景下,jQuery 應運而生。它的初衷是為開發者提供一個統一的、能夠跨瀏覽器工作的 API。
在 jQuery 出現之前,如果你想處理 JS 事件,你需要為幾種不同的瀏覽器標準編寫不同的代碼,以確??鐬g覽器兼容。
以下是一個展示 2005 年網絡開發難題的簡短代碼示例:
function myEvent() {
alert('click event');
}
// 檢查瀏覽器是否支持 addEventListener 方法。
if (elem.addEventListener) {
// 為元素添加點擊事件監聽器,使用標準的方法。
elem.addEventListener("click", myEvent, false);
} else if (elem.attachEvent) {
// 為元素添加點擊事件監聽器,用于不支持 addEventListener 的老舊瀏覽器(如IE8及以下版本)。
elem.attachEvent("onclick", myEvent);
}
jQuery 的實施效果非常好,它通過簡潔強大的 API,解決了跨瀏覽器的兼容問題,使開發者無需操心這些問題。它的創新之處在于,它以瀏覽器的功能而非用戶代理為目標,這一策略極大地改變了游戲規則。
上面的代碼可以用 jQuery 重新編寫,無需考慮瀏覽器兼容問題:
/**
* 通過 jQuery 綁定點擊事件。
*/
$(function() {
$('#elem').click(function() {
alert('click event');
});
});
我記得第一次在 QuirksMode 上讀到關于 jQuery 的文章時,對其簡單的使用方式感到震驚。我只需添加一個腳本標簽,一切問題即刻迎刃而解,僅需一行代碼。
jQuery 迅速成為 Web 開發者的新寵,廣泛應用并推動了我們今天熱愛并使用的許多現代 Web 標準的發展。
我們不應忘記,盡管有人認為 jQuery 的流行主要得益于 WordPress,但 jQuery 仍是當今使用最廣泛的 JavaScript 框架之一。
在解決了瀏覽器 JavaScript 兼容性問題之后,jQuery 的下一步發展是其插件系統。
為了保持核心庫的精簡,jQuery 設計了一個插件系統,允許開發者擴展其功能。開發者們借此創建了眾多可復用的UI組件,例如著名的 jQuery 日期選擇器。
4.Backbone.js 與 AngularJS 登場
Backbone.js 于 2010 年問世,它是最早為客戶端 Web 應用帶來結構化設計,并邁向單頁應用(SPA)的先鋒之一。
一些開發者認為 Backbone 的重要貢獻在于促進了前端開發理念的轉變,雖然不能忽視 YUI 庫在這方面的早期嘗試。
在 Backbone.js 出現之前,網站主要通過服務器端應用推送 HTML 和 CSS 到客戶端瀏覽器,并通過 JavaScript 來“漸進式”增強用戶體驗,這就是“漸進增強”的由來。
隨著網站交互性的增強,需要在客戶端維護一個與服務器端和 DOM 同步的數據模型。Backbone.js 通過其基于 MVC(模型-視圖-控制器)的架構設計來滿足這一需求,這標志著基于組件的 Web 開發的一個重要里程碑。
另一方面,AngularJS 作為谷歌的創新產品,首發于 2010 年,其后續版本 Angular 2+ (從2016年開始,統稱為Angular)不同于 Backbone.js,它不是一個庫。
Angular 是一個功能全面的 JavaScript 框架,它引入了“指令(directives)”這一概念(后被 Vue 采用),提供了一種擴展 HTML 語法的優雅機制,允許開發者創建自定義 HTML 元素,這在基于組件的開發中是一個劃時代的概念。
通過引入“指令”,Angular 實現了可重用組件的創建,顯著提高了代碼的維護性和可讀性,正如其市場宣傳所述。
總的來說,Backbone.js 和 Angular 都在 Web 開發社區中引發了關于如何創建更高效、可維護和可擴展的客戶端應用的重要討論,并推動了基于組件的 Web 開發的熱潮。
5.利用 CoffeeScript 進行轉譯
CoffeeScript 在 JavaScript 框架演進中扮演了關鍵角色,主要體現在它引入了“轉譯”的概念,即源到源的編譯方式。CoffeeScript 的作者也是 Backbone.js 的開發者。
對于那些厭倦了處理 JavaScript 的復雜性和各種特殊情況的開發者來說,CoffeeScript 提供了一個解決方案:創造一種全新的語言,然后將這種語言轉譯成 JavaScript,使其能夠在瀏覽器中運行。
比如,JavaScript 中的作用域和閉包常常讓新手和經驗不足的開發者感到困惑。尤其是 var 關鍵字導致的變量提升問題,以及函數作用域與塊級作用域的差異。
CoffeeScript 引入了 let 和 const,這兩個關鍵字幫助定義塊級作用域變量,減少了由于作用域引起的常見錯誤。
除了提供更簡潔的語法外,CoffeeScript 引入的高級功能,如解構賦值、類和數組推導,極大地簡化了 Web 組件的構建過程。這些特性最終被納入現代 JavaScript 中,對 JavaScript 的發展產生了深遠的影響。
6.Node.js,JavaScript 的顛覆之路
Node.js 可以視為一股助燃劑,點燃了客戶端技術快速發展的潛行之火,推動了今天我們使用的多種現代 JavaScript 標準的廣泛采納。
在 Node.js 出現之前,JavaScript 主要是一種客戶端語言,用來增強網頁的交互性。
Web 開發者在 JavaScript 開發工具方面選擇有限,大多依賴于瀏覽器的運行時執行,并常常需要借助其他服務器端技術手動進行代碼的壓縮和合并。
Node.js 的誕生使得 JavaScript 得以跨越到服務器端,允許開發者在瀏覽器環境之外執行 JavaScript 代碼。
盡管 Node.js 的初衷是展示 JavaScript 的通用性,并承諾能夠簡化 Web 開發流程、優化代碼、捕獲錯誤,并通過在服務器和客戶端使用同一編程語言來自動化重復性任務,但實際上它觸發了相反的趨勢。當然,這種趨勢的形成并非 Node.js 所能控制。
Node.js 提供了開發各種工具的平臺,催生了包括 Grunt、Gulp、Webpack、Babel 等在內的豐富的包生態系統。
毫無疑問,Node.js 的另一個重要創新是其包管理器 NPM,該管理器極大地簡化了 JavaScript 庫和工具的安裝與分發過程,為 JavaScript 的擴展和應用提供了極大的便利。
7.React 和前端工具的瘋狂演進
我們已經進入了單頁應用(SPA)、互動豐富的 Web 應用領域,React 在這里無需過多介紹了吧。
雖然 React 并未引領我們今天前端開發復雜的生態系統,但它確實改變了我們的開發方式,使之更加偏向于 React 的專有方式。
隨著對創建高交互性和高性能 Web 應用的需求不斷增加,圍繞模塊化JavaScript 代碼開發了越來越多的工具。這種對技術的追求在一定程度上塑造了我們今天所見的開發環境。
我第一次接觸 React 是在 2014-2015 年,客戶的技術領導完全接受了 React 早期的 Flux 架構。
當時我強烈反對使用 JSX,這反映了更廣泛的 Web 開發社區的看法:“哪個理智的開發者會把 HTML 嵌入JavaScript中?!”
但現實就是這樣,HTML 最終被嵌入到 JS 中,接著是 CSS,像 Web 開發中許多事情一樣,你不得不逐漸接受它。
現在,管理和響應瀏覽器中的應用狀態并對其作出反應,已成為主流。
React 開啟了這一變革,Vue 則繼續推動這種以 JavaScript 為中心的開發轉變,鼓勵開發者使用 JavaScript 編寫一切,包括標記語言和樣式,并提倡“一次創建,隨處使用”的組件理念(至少這是最初的承諾)。
React 通過 React Native 則更進一步,承諾可以在包括移動端在內的任何平臺上使用一次編寫的代碼。
React 還加劇了前端開發中的反饋循環趨勢,隨著越來越多的工具和 JS 模塊被創建出來,為了在進一步改進或修復廣泛使用的主要 JS 框架的不足,這些框架的使用往往未經過深思熟慮。
注:如果你有時間,不妨觀看 React.js 的紀錄片,其拍攝和制作質量都很高。
React.js 紀錄片:https://www.youtube.com/watch?v=8pDqJVdNa44
8.TypeScript,復雜類型的系統修補
與 CoffeeScript 相似,TypeScript 是一種源到源的編程語言,并非 JavaScript 框架,但它在這些框架的演進中起到了關鍵作用,這一點得到了微軟和無數開發者的認同。
編程語言中的類型安全極為重要,但我對于在本質上應支持動態類型的 JavaScript 上強加靜態類型持保留態度,畢竟這不應視為缺陷。
在這方面,我贊同 DHH 對 TypeScript 的批評,他指出了TypeScript的局限性,解釋了為什么他們的產品中避免使用它。
DHH 對 TypeScript 的批評:https://world.hey.com/dhh/turbo-8-is-dropping-typescript-70165c01
在 TypeScript 出現之前,JavaScript 以其在大規模項目中的難以管理而聞名,這不僅僅是因為缺少靜態類型。
然而,靜態類型的缺失并沒有讓 JavaScript 更出色,反而隨著項目的擴大,調試和維護代碼的復雜性也在增加。
TypeScript 引入了如接口、枚舉類型和可選參數等強大功能,這些特性對于管理復雜的 JS 項目至關重要。
此外,TypeScript 還提供了開發工具支持,如更準確的自動完成、重構能力等功能,大大提高了開發效率(同時,自動完成和 lint 規則也可以通過 JSDoc 設置)。
但是,TypeScript 本質上是在 JavaScript 之上增加了一層,帶來了可能并非對每個項目或開發團隊都必要或適宜的復雜性和開銷。
盡管 TypeScript 提供了許多增強功能,但學習一種全新的語言及其語法、規則和最佳實踐的代價也不小。這對于小型項目或團隊來說,可能是一個不小的挑戰。
TypeScript 要求開發者為變量、函數返回值和參數注明類型。雖然這在大型項目中有助于提高代碼的可讀性和調試性,但在小型項目中可能會拖慢開發速度。
總之,TypeScript 引發了關于在 JavaScript 中引入可選靜態類型的討論,促進了語言的成熟,這無疑是一件好事。
9.Svelte,為前端開發帶來一絲光明
隨著前端開發者對 JavaScript 生態系統的普遍疲勞,Svelte 應運而生,帶來了新的活力。
Svelte 試圖解決傳統框架導致的代碼膨脹問題。到目前為止,React、Angular 乃至 Vue 都已被視為傳統框架。
Svelte 還試圖降低學習難度,其他框架和庫的復雜性往往使初學者望而卻步。與之形成對比的是,Svelte 的設計宗旨是直觀易懂。
通過簡化的語法和減少的樣板代碼,即使是只有基礎 HTML、CSS 和 JavaScript 知識的開發者也能在較短時間內掌握 Svelte。
Svelte 也可以看作是一種編譯類 HTML、CSS 和 JS 代碼的編程語言,而非解析常規 HTML/CSS/JS 的解析器。
如果把 Svelte 視為一種編程語言,那么我們寫的代碼雖然看起來像 HTML、CSS 和 JS,但實際上并非如此。
/**
* Svelte 組件示例。
*/
<script>
let count = 0;
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
<style>
button {
color: blue;
}
</style>
這就是 Svelte 為什么被歸類為 devDependencies 的原因,因為與 React 等不同,我們在生產環境中不需要 Svelte 的代碼。
通常,在使用傳統 JavaScript 框架的情況下,客戶端瀏覽器需要加載并執行整個 JavaScript 包,用戶才能與應用互動。
這個過程可能很慢,尤其在移動或網絡慢的環境下,可能會對用戶體驗產生不利影響。SvelteJS 通過在構建過程中完成繁重的工作來解決這個問題。
與 React 不同,Svelte 在如何處理事務上持有更明確的立場,這在 SvelteKit 中表現得尤為明顯。
此外,Svelte 是首批開始探討多頁應用(MPAs)在客戶端開發中地位的主要框架之一。在此之前,MPAs 被視為過時的開發方法,不再被開發者采用。
盡管如此,Svelte 仍在前端開發的復雜局勢中嘗試帶來一絲光明。
10.Htmx,前端開發的新視角
如果你還不熟悉 htmx,那也無妨。它是一個較新的 JavaScript 框架,更準確地說,它是對現代前端開發的一種全新思路。
盡管 CoffeeScript、TypeScript 和 Svelte 試圖通過使用類似 JavaScript 的語言來修復 JavaScript 的缺陷,htmx 的開發者則選擇了一條不同的道路——從零開始,完全不使用 JavaScript。
Htmx 使得 Web 開發者能夠直接在 HTML 中使用 AJAX、CSS Transitions、WebSockets、JS Events 和 SSEs(服務器推送事件),無需編寫大量的 JavaScript。
這種方法雖然不是全新的,但它以一種無縫的方式將靜態 HTML 轉化為動態內容,為 Web 應用增強提供了新的途徑。
與其他復雜的 JavaScript 框架不同,htmx 提倡一種更簡單的 Web 開發方法,通過在 HTML 中直接實現動態 UI 交互,顯著減少了對 JavaScript 的依賴。
這種方法強化了 Web 開發中的漸進增強原則,即使用 HTML 和 CSS 構建基礎和布局,而將 JavaScript 保留為增加必要交互性的輕量級工具。
Htmx 的簡潔性可能令人不安,我們曾經深陷前端開發的復雜中不得自拔,而 htmx 提醒我們,許多它所采用的技術實際上早已存在,只是被我們忽視了。
通過后端語言的應用,開發者可以在后端保持數據和狀態,而前端則保持 UI 的動態性和響應性,這才是最理想的分工。
這種回歸簡潔的趨勢對年輕開發者而言是一件好事,他們將發現在不依賴現代 JavaScript 框架的情況下進行前端 Web 開發的樂趣。盡管如此,這并不意味著 React、Vue、Svelte 和 Angular 會很快消失,我們需要循序漸進地接受這一變化。
全棧開發者的歸來預示著前端開發領域正在迎來更全面的技能要求和新的發展機會。
11.未提及的重要技術
我知道我遺漏了許多在現代前端開發中具有重要影響的技術,比如 Alpine、Astro、Babel、Bun、Dojo、EmberJS、Esbuild、ES6、ExtJS、Express、Gatsby、GraphQL、Jamstack、KnockoutJS、Lit、MeteorJS、MERN、MooTools、Next、Nuxt、Parcel、Polymer、Preact、PWAs、Remix、REST、RollupJS、Rome、Ruby on Rails、RxJS、SproutCore、Sass、Skypack、Snowpack、SolidJS、Stencil、Stylex、Vite、Vue、Zig 等等。這些技術在現代前端開發中都以某種方式做出了貢獻。
主要原因有:1) 我無法一一涵蓋所有內容,2) 很多技術有相似的理念,最后 3) 我對其中許多技術不夠熟悉,難以做出深入的評價。