The only constant in the world is change.世界上惟一不變的是變化。--《誰動了個人奶酪》做者 斯賓塞·約翰遜javascript
IT 行業變化太快了,尤爲是前端開發(Frontend Development)。若是能穿越回 10 年前,碰上一位 Web 開發軟件工程師,他必定會告訴你玩轉前端就是精通 jQuery 和搞定 IE 瀏覽器兼容性。不過隨着前端的不斷髮展,jQuery 遭遇 「官方逼死同人」 逐漸退出歷史舞臺(元素選擇和操做被標準的 DOM API 所統一);而飽爲詬病的 IE 瀏覽器兼容性問題,由於 IE 市場的逐漸萎縮以及一些兼容性工具(Polyfill)的出現,讓其從以前的核心優化問題降級爲現在的瘙癢問題,再也不成爲前端工程師的標配。css
現在的前端開發,有着玲琅滿目的專業術語和紛繁複雜的技術生態,可能會讓初入前端開發的工程師感到惴惴不安:要學的東西實在是太多了。如今的前端工程師若是不瞭解 Webpack、Babel、Node.js、NPM/Yarn、ES6/七、React/Vue、Sass/Less、TypeScript、ESLint、Canvas/SVG 等現代化前端知識,就難以讓人信服本身的專業背景。2021 年的前端工程師多是真正意義上的工程師(Engineer),他們一般須要運用大量的專業知識來解決工程化問題,包括如何將項目進行模塊化,如何設計組件間的交互,如何提升可複用性,如何提高打包效率,優化瀏覽器渲染性能,等等。他們再也不像之前,只須要 HTML/CSS/JS 一個套路來開發靜態頁面。html
本文將着重就現代前端開發的主題,來詳細介紹前端工程化的各個重要技術,幫助讀者瞭解現代前端頁面的複雜和多樣性是如何構造的。本文是一篇關於前端工程的科普文,即便你不瞭解前端技術,也能夠從本文受益。前端
要說現代前端開發跟 10 年前最大的不一樣點是什麼,我確定會說是打包部署(Bundling & Deployment)。生活在前端 「石器時代」(jQuery 主流時期)的開發者確定很難想象現在的前端項目須要編譯(Compile)。之前的大部分 Web UI 是經過 MVC 的方式來提供給用戶的,前端頁面大部分是經過後端模版渲染生成靜態資源(HTML/CSS/JS)不經任何加工提供給瀏覽器的。也就是說,當時前端的靜態資源至關於後端服務表現層(Presentation Layer)的一部分,複雜的交互一般都由後端來完成。所以前端靜態資源一般很是簡單,不須要通過複雜的編譯打包,最多就是壓縮(Minify)成更小的文件。vue
而如今的狀況徹底不一樣了,用戶對於交互性的需求逐漸增大,一般不肯意花過多的時間來等待頁面響應。傳統的 MVC 模式受限於網絡傳輸,一般須要幾百毫秒甚至更多來完成一次頁面導航,而這是很是影響用戶體驗的。所以,前端項目逐漸分離出來,單獨做爲一個應用運行在瀏覽器中,交互在瀏覽器端進行,速度很是快。可是,複雜交互都集中在前端裏面,讓前端項目變得更復雜,更臃腫,也更難以管理。所以,龐大的項目源碼須要被壓縮成很小的靜態文件,儘量少的佔用網絡資源傳輸給瀏覽器。如今稍微大一點的前端項目的依賴文件就會超過 500MB。相信你不會傻到將這麼多文件一股腦塞給用戶吧!java
所以,你須要一個很是強大的打包和編譯工具。Webpack 是如今比較主流的打包工具,可以配合編譯工具(例如 Babel)將各類類型的項目源代碼文件(例如 .vue、.ts、.tsx、.sass)打包成原生的 .js、.css、.html 等靜態文件,直接提供給瀏覽器運行。下圖是 Webpack 官方網站的流程示意圖。Webpack 經過檢查源代碼文件的各類依賴關係,分析編譯後生成對應的靜態資源文件。這就跟編譯 Java、C# 代碼編譯是一個道理。node
Webpack 的配置由一個 JavaScript 文件來定義,文件名一般爲 webpack.config.js
。下面是一個最基礎的 Webpack 配置。react
const path = require('path'); module.exports = { entry: { main: './src/main.js' // 入口文件 } output: { path: path.resolve(__dirname, 'dist'), // 打包後的輸出路徑 filename: 'bundle.js' // 打包後的輸出文件名 }, module: { rules: [ { test: /\.css$/, use: 'css-loader' }, // .css 文件轉換模塊 { test: /\.ts$/, use: 'ts-loader' } // .ts 文件轉換模塊 ] } };
這段配置代碼定義了打包的入口(Entry)、輸出(Output)以及編譯所用到的加載規則(Rules),這些均可以經過一個配置文件來完成。定義好配置文件 webpack.config.js
,在項目根目錄下執行 webpack
命令,就會默認加載該配置文件,而後讀取源代碼並打包爲編譯後的靜態文件。您可能會注意到,有 module.rules
這個數組結構的配置項,這裏能夠定義各類文件類型的加載器(Loaders),也能夠看做編譯器。在這個例子中,css-loader
是處理 .css 文件的加載器,它會將 @import
、url()
、import
、require
等關鍵詞轉換爲 原生 CSS/JS 中兼容的代碼。而爲了讓 css-loader
生效,您須要在項目根目錄下運行 npm install css-loader --save
來安裝該加載器。同理,處理 .ts 文件的 ts-loader
也須要經過 npm install ts-loader --save
來使其生效。其實,爲了讓 Webpack 能處理各類文件類型(例如 .vue、.tsx、.sass),一般都須要安裝對應的加載器,這其實給了 Webpack 很是強的可擴展性。經過安裝加載器的方式,讓不一樣類型的文件統一成原生前端代碼,這也使咱們可以很是有效的管理複雜而龐大的前端項目。webpack
因爲本文不是一個參考指南,所以關於 Webpack 的具體配置本文不打算詳細介紹。若是須要了解 Webpack 的更多內容,能夠去 Webpack 官方文檔(https://webpack.js.org/concepts)深刻研究。固然,前端打包工具並不止 Webpack 一種,還有其餘一些比較受歡迎的工具,例如 Rollup.js、Gulp.js、Parcel.js、ESBuild 等等。感興趣的讀者能夠深刻研究一下。git
Webpack 以及其餘打包工具的驅動引擎是 Node.js,也就是說它們是做爲 Node.js 的一個依賴來運行的。其實,任何一個現代化的前端項目,都離不開 Node.js,還有其包管理系統 NPM。咱們將在下一個小節介紹前端項目的模塊化,包括 NPM。
模塊化(Moduarization)是任何技術工程項目中很是重要的概念。一個複雜的穩定運行的大型系統一般是由多個子模塊一塊兒構成的,它們之間相互通訊、共同協做來完成一些很是複雜的邏輯或任務。複雜性爲維護人員帶來的麻煩一般是非線性的,也就是說,在系統成長到必定規模的時候,要增長單位規模所須要花費的成本會成指數級增長。若是咱們不採起必定措施限制維護成本,那這樣規模的項目幾乎是不可維護的。爲了讓開發者可以有效管理大型項目,咱們的作法一般是減小複雜性和可理解性,儘量的減小系統複雜性增長的速度。而一種有效下降複雜性的方式,就是分而治之,對於軟件項目來講就是模塊化。模塊化讓各個負責相同或相似功能的子系統獨立運行(高內聚),並適當開放一些接口提供給其餘子模塊(低耦合)。這樣整個大型系統由多個子模塊描述,而這些子模塊都有各自的特性和功能,讓維護人員可以準確的定位到各功能對應的模塊,從而大大減小了維護成本。「高內聚,低耦合」 是模塊化的核心理念,其最終的目的,是下降系統複雜性和提升可維護性。模塊化對於日漸複雜並且動輒幾百兆代碼的前端項目來講,是很是很是重要的。
對於前端項目來講,NPM(Node Package Manager)不可或缺的前端項目構建工具。NPM 顧名思義是 Node.js 的包管理工具,相似於 Python 的 pip,Java 的 Maven,C# 的 Nuget,等等。對於一些已經存在的模塊或功能,咱們不須要從頭開始編寫,由於軟件工程界所倡導的 DRY 原則(Don't Repeat Yourself),不然咱們會花大量的時間在重複造輪子上。NPM 就是前端項目中的依賴管理工具,它可以幫助你安裝構建前端項目所須要的包和庫,而後再經過前文的 Wepback 等打包工具將源代碼編譯成原生前端靜態文件。
描述前端項目依賴的配置文件叫作 package.json
,相似於 Python 中的 setup.py
,Java 裏的 pom.xml
,能夠定義項目的依賴包、運行入口、環境要求等等。package.json
能夠手動生成,也能夠用 npm init
的方式建立。下面是一個樣例 package.json
文件。
{ "name": "crawlab-frontend", "version": "0.1.0", "private": true, "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", "lint": "vue-cli-service lint", "test": "jest" }, "dependencies": { "@fortawesome/fontawesome-svg-core": "^1.2.32", "@fortawesome/free-brands-svg-icons": "^5.15.1", "@fortawesome/free-regular-svg-icons": "^5.15.1", "@fortawesome/free-solid-svg-icons": "^5.15.1", "@fortawesome/vue-fontawesome": "^3.0.0-2", "@popperjs/core": "^2.6.0", "@types/codemirror": "^0.0.103", "@types/md5": "^2.2.1", "atom-material-icons": "^3.0.0", "codemirror": "^5.59.1", "core-js": "^3.6.5", "element-plus": "^1.0.1-beta.7", "font-awesome": "^4.7.0", "md5": "^2.3.0", "node-sass": "^5.0.0", "normalize.css": "^8.0.1", "vue": "^3.0.0", "vue-i18n": "^9.0.0-beta.11", "vue-router": "^4.0.0-0", "vuex": "^4.0.0-0" }, "devDependencies": { "@babel/preset-typescript": "^7.12.7", "@types/jest": "^26.0.19", "@typescript-eslint/eslint-plugin": "^2.33.0", "@typescript-eslint/parser": "^2.33.0", "@vue/cli-plugin-babel": "~4.5.0", "@vue/cli-plugin-eslint": "~4.5.0", "@vue/cli-plugin-router": "~4.5.0", "@vue/cli-plugin-typescript": "~4.5.0", "@vue/cli-plugin-vuex": "~4.5.0", "@vue/cli-service": "~4.5.0", "@vue/compiler-sfc": "^3.0.0", "@vue/eslint-config-typescript": "^5.0.2", "eslint": "^6.7.2", "eslint-plugin-vue": "^7.0.0-0", "sass-loader": "^10.1.0", "scss-loader": "^0.0.1", "typescript": "~3.9.3" } }
其中,比較重要的是 dependencies
和 devDependencies
這兩個配置項,它們定義了該項目所依賴的包。它們是 Key-Value 的形式,Key 爲依賴的包名,Value 是對應的依賴包的版本號或者版本號匹配表達式。當項目建立好後,執行 npm install
就能夠自動的將依賴包從包託管網站 https://npmjs.com 上拉取下來。全部安裝好的模塊會出如今 node_modules
目錄下,每一個包對應的目錄名稱以其包名命名。當咱們打包編譯源代碼時,項目構建工具會自動分析源代碼的依賴,並從 node_modules
找到對應的模塊來進行編譯和構建。
scripts
配置項是項目開發、調試、構建、測試、部署的命令行別名(Alias),幫助您快速啓動項目。它也是 Key-Value 的形式,Key 爲別名,Value 爲具體對應的執行命令。例如,根據上面的配置,若是執行 npm run build
,至關於執行了 vue-cli-service build
,即經過 vue-cli-service
這個官方命令行工具來打包編譯前端項目(vue-cli-service
實際上是針對 Vue 項目封裝的 Webpack 構建工具)。
除了前面提到的要點,NPM 還有其餘不少配置功能。詳細信息能夠參考官方文檔(https://docs.npmjs.com)。若是你想更深刻了解前端包管理,推薦學習一下 Yarn,這是 Facebook 開源的包管理工具,跟 NPM 很是像,但有一些實用功能,例如依賴緩存。
若是說上面說的 NPM 以及包管理系統是宏觀層面項目間的模塊化,那麼這個小節介紹的項目結構則是微觀層面項目內的模塊化。爲了保證前端項目代碼的可維護性,前端開發工程師一般須要掌握清晰而合理的代碼組織方式,包括如何對不一樣類型文件或組件進行分類和管理,以及如何組織項目目錄的層次和結構。下面是一個典型的 Vue3 的前端項目代碼結構。
. ├── LICENSE ├── README.md ├── babel.config.js // Babel 編譯器配置文件 ├── jest.config.ts // Jest 測試工具配置文件 ├── package.json // 項目定義文件 ├── public // 公有靜態目錄 │ ├── favicon.ico │ └── index.html ├── src // 源代碼根目錄 │ ├── assets // 靜態文件目錄,包括 .scss、.svg、.png 等 │ ├── components // 組件 │ ├── i18n // 國際化 │ ├── interfaces // 類型定義 │ ├── layouts // 佈局 │ ├── main.ts // 主入口文件 │ ├── router // 路由 │ ├── shims-vue.d.ts // Vue 的 TS 適配文件 │ ├── store // 狀態管理 │ ├── styles // 樣式 │ ├── test // 測試 │ ├── utils // 公共方法 │ └── views // 頁面 ├── tsconfig.json // TS 配置 └── yarn.lock // yarn 依賴鎖定
能夠看到,一些基礎配置文件都在根目錄下,src
目錄是源代碼的主要目錄,能夠理解爲核心代碼都在 src
目錄下。而在 src
目錄下,有一些子目錄,這裏是前端項目的核心模塊,包括頁面(Views)、路由(Router)、組件(Components)、佈局(Layouts)、狀態管理(Store)等。固然,不是每一個項目都是同樣的組織形式,可能或多或少會有一些不一樣,但頁面、組件、路由這些一般都是重要的模塊須要獨立出來。組件通常是可複用的,是頁面的組成部分;路由是實現前端導航匹配頁面的功能;頁面就是各類網頁的實際內容。其實,這種代碼的組織形式跟傳統的後端項目相似,也是將負責不一樣功能的高內聚的模塊獨立出來,各自造成同一類型的結構。
這樣作的好處在於,開發者能夠經過對所要解決的問題進行分類,從而可以精確的定位到相關的模塊,快速完成開發任務或解決疑難問題。這就跟整理家裏雜物或者文件歸檔同樣,若是常常收拾整理,會讓生活或者工做環境變得更層次分明。
固然,也不是說傳統的前端項目就沒有模塊化的概念,只是在 jQuery 時代,如何進行模塊化甚至需不須要模塊化都沒有一個統一標準。若是你在 10 年前作過前端項目,你應該對那些臭不可聞的 「屎山」 代碼深有體會。現在,隨着前端技術的不斷髮展,前端行業已經衍生出不少幫助前端工程師進行工程化的工具和方法論,除了本小節的模塊化之外,還有接下來將要介紹的前端框架,也就是如今熟知的 React、Vue、Angular 三大框架以及其餘一些小衆的框架。
不少時候,一個新事物的誕生和走紅絕對不是偶然的。就像 2006 年橫空出世的 jQuery 同樣,它解決了當時用原生方法操做 DOM 的痛點。jQuery 經過簡潔的 API 和高效的性能,成爲當時前端界的標配。要說 jQuery 的成功,是創建在當時原生 JavaScript 的缺陷上:囉嗦而臃腫的語法,複雜而難以理解的設計模式,瀏覽器標準的不統一。這給當時的 Web 開發人員帶來了巨大的痛苦。而 jQuery 做爲 JavaScript 的一個輕量級的工具庫,很大程度上彌補了 JS 的不足,所以獲得了大量開發者的歡迎,而且隨着互聯網產業的發展成爲了後來不少年的前端霸主。不少其餘的知名第三方庫,例如 Bootstrap,也是創建在 jQuery 上的。
在愈來愈多的開發者開始擁抱 jQuery 時,很多人也開始抱怨它的不足。在用戶體驗變得愈來愈重要的趨勢下,部分開發者開始將本來一些後端的交互邏輯遷移到前端,以追求更快的響應速度和更流暢的用戶體驗。而爲了達到這個目的,很多開發者開始大量利用 jQuery 經過 Ajax 異步請求來實時渲染前端頁面,也就是用 JS 代碼來操做 DOM。而這一變化則帶來了大量 jQuery 用戶的抱怨:他們認爲用 jQuery 實現帶有複雜交互邏輯的 UI 是一件很是頭疼的事情。首先,jQuery 嚴重依賴於 DOM 元素的 CSS 或 XPath 選擇器,這爲項目模塊化帶來了很是大的麻煩:全部的元素對於一個前端應用來講幾乎是全局,這意味着 class
、id
等屬性對於項目穩定性來講變得異常敏感,由於稍不注意你可能就誤改了不應修改的元素,污染了整個應用。其次,jQuery 實現前端交互的原理是直接操做 DOM,這對於簡單應用來講還好,但若是前端界面有大量須要渲染的數據或內容,或者要求頻繁的改變界面的樣式,這將產生很是大的性能問題,將致使瀏覽器卡頓,嚴重影響用戶體驗。第三點,jQuery 沒有一個編寫前端項目的統一模式,程序員們能夠根據本身的喜愛隨意發揮,這個也是形成前端應用 Bug 橫飛的緣由之一。總的來講,大量使用 jQuery 來實現前端交互使前端項目變得很是脆弱(Fragile)。
2009 年,一位 Google 工程師開源了他的業餘項目 AngularJS,這個全新的框架給當時被 jQuery 統治的前端行業帶來了革命性的進步。當時這位工程師只用 1,500 行 AngularJS 代碼在 2 周內實現了 3 人 花了 6 個月開發的 17,000 行代碼的內部項目。因而可知這個框架的強大。AngularJS 的主要特色是 HTML 視圖(HTML View)與數據模型(Data Model)的雙向綁定(Two-way Binding),意味着前端界面會響應式的隨着數據而自動發生改變。這個特性對於習慣寫 jQuery 的前端工程師來講是既陌生又期待的,由於這種編寫模式再也不要求主動更新 DOM,從而將節省大量主動操做 DOM 的代碼和邏輯,這些 AngularJS 所有幫你自動完成了。下面是 AnguarJS 雙向綁定的示意圖。
AngularJS(1.0 版本的名稱,後來改名爲 Angular)能作到一部分組件化(Componentization),但支持得並不完整。利用 Directive 來組件化一些公共模塊會顯得力不從心。這給後來的兩大框架 React(由 Facebook 開發)以及 Vue(由前 Google 工程師尤雨溪開發)帶來了靈感和機遇。
2013 年,Facebook 在 JS ConfUS 上公開發布了 React 這個全新前端框架。React 獨樹一幟,創造了虛擬 DOM(Virtual DOM)的概念,巧妙的解決了前端渲染的性能問題;同時,React 對組件化支持得很是到位。另外一方面,React 的數據-視圖單向綁定(One-way Binding)很好的解決了一致性問題,也很是好的支持 TypeScript,這可以爲開發大型前端項目帶來穩定性和健壯性。不過也所以造成了不小的門檻。React 初學者一般須要理解大量的基礎概念,例如 JSX,才能順利的編寫 React 應用。
而 1 年之後,後起之秀 Vue 由前 Google 工程師尤雨溪公開發布。它另闢蹊徑,在吸取 React 與 AngularJS 優勢的同時,也作了一些優秀的創新。Vue 把視圖(HTML)、數據模型(JS)和樣式(CSS)整合到一個 .vue 文件中,並沿用 AngularJS 的雙向綁定,這下降了前端開發的門檻。若是你寫過 AngularJS,你會很是容易上手 Vue。另外,Vue 在組件化的支持上也作得很是棒。最近發佈的 Vue3 也加入了 TypeScript 的支持,讓其可以充分支持大型前端項目。想進一步瞭解 Vue3 的讀者能夠關注 "碼之道" 公衆號(ID: codao),查看歷史文章《TS 加持的 Vue 3,如何幫你輕鬆構建企業級前端應用》,裏面有關於 Vue3 新特性以及如何利用它構建大型項目的很是詳細的介紹。
自 2.0 版本開始,AngularJS 改名爲 Angular,優化了以前的部分不足,並且全面擁抱了 TypeScript。Angular 與 AngularJS 從語法上來看幾乎是兩個徹底不一樣的框架。Angular 強制要求使用 TS 開發,這使其變得很是適合構建大型前端項目。不過,這也讓初學者須要同時學習 TS,以及 Angular 中自己很是複雜的概念,使得其學習曲線很是陡峭。
如下是對目前這三大前端框架的總結。
屬性 | React | Vue | Angular |
---|---|---|---|
創始者 | 尤雨溪(前 Google 工程師) | Misko Hevery(Google) | |
首次發佈時間 | 2013(距今 8 年) | 2014(距今 7 年) | 2009(距今 12 年) |
國內使用量 | 高 | 高 | 低 |
國外使用量 | 高 | 低 | 中 |
上手難度 | 高 | 低 | 很是高 |
適用項目規模 | 大中型 | 大中小型 | 大型 |
生態豐富度 | 高 | 中 | 低 |
數據綁定 | 單向 | 雙向 | 雙向 |
TypeScript | 支持 | 支持 | 強制要求 |
文件大小 | 43KB | 23KB | 143KB |
Github Stars | 145k | 158k | 58k |
優勢 | 快速,穩定,生態好 | 簡單,靈活性高,易學習,文檔詳細 | 複用性強,強制 TS,適合企業級項目 |
缺點 | 學習成本高,文檔更新慢 | 穩定性略差,社區不大 | 複雜,很是高的學習曲線,文檔不詳細 |
React、Vue、Angular 現在在前端領域裏已成爲前端工程師必須瞭解、掌握甚至精通的前端框架。不過,隨着移動端的崛起,以及新技術的出現,能夠預見到這種 「三足鼎立」 的趨勢將在將來幾年發生巨大的變化。WebAssembly 的出現給前端傳統的 HTML/CSS/JS 技術帶來了挑戰;混合開發(Hybrid Development)、小程序(Mini-Program)、PWA 等技術讓前端工程師可以涉足移動端開發;新興的前端框架,例如 Svelte、Elm.js、ReasonML 等,隨着知名度的不斷增長,均可能會對現有的技術產生影響。總之,正如本文開頭所說的,「The only constant in the world is change」。
對於現代化前端工程來講,組件化是一個核心概念。組件化其實是前端 UI 界面的模塊化。對於複雜的前端應用來講,不少組件,例如按鈕、導航、輸入框等,都是能夠複用的 UI 模塊,能夠用在各類各樣的頁面中。另外,組件以內還能夠套用子組件,子組件中還能夠套用子子組件,這使得前端界面的組織變得很是靈活。若是你設計穩當,當面對老闆或產品經理的需求變動時,例如佈局調整、樣式變動、功能擴展等,你均可以從容不迫的應對。組件化由於過重要了,每一個前端工程師都須要掌握其中的設計原理,無論你使用哪一種前端框架。
若是目標是實現一個大型的擴展性強的前端項目,前端工程師除了須要提早組織好代碼結構(佈局、組件、路由)等,還須要考慮設計一些基礎組件,簡化後續的開發與維護工做。其中,最基礎的組件應該算是佈局組件(Layout Components)了,你可能須要設計頂部(Header)、側邊欄(Sidebar)、主容器(Main Container)以及底部(Footer)等等。固然,一些經常使用的功能組件也須要考慮,例如輸入框(Input)、表單(Form)、彈出框(Modal)等等。建議不要重複造輪子,你能夠根據本身的框架選擇合適的 UI 框架,例如 React 的 Ant Design,Vue 的 ElementUI,只有比較特殊的組件須要本身來實現。
另外,前端工程師也須要很是熟悉如何設計組件間的通訊。通常的父子組件間通訊能夠經過屬性傳遞(Property Propagation)以及事件發射(Event Emission)來實現。對於多層間的通訊,能夠考慮用 Context 或 Event Bus 來處理。兄弟組件間的通訊一般是用狀態管理(Store)來實現。
固然,組件化的設計模式並非千篇一概,前端工程師們通常都從實踐和借鑑中積累經驗,造成本身的一套知識體系。對於初學者來講,能夠看看前人們發佈的開源框架,例如 Ant Design 或 ElementUI,裏面的源碼以及實現過程是公開的,研究裏面的源代碼能夠幫助你有效掌握已經通過項目實踐考驗的設計理念。
JavaScript 在前端開發中扮演着很是重要的角色,是交互邏輯的核心。然而,JavaScript 是一個弱類型動態語言,意味着各類基礎類型之間能夠互相轉化,所以用 JS 編寫的程序的穩定性和健壯性比較堪憂。這對於構建大型前端應用來講是個致命的缺點。幸運的是,微軟於 2012 年發佈了 TypeScript,它能夠利用靜態代碼檢測機制將 JavaScript 用強類型約束起來。TypeScript 是 JavaScript 的超集,也就是說,TS 包含 JS 的所有語法和特性,而且在此基礎上加入了類(Class)、接口(Interface)、裝飾器(Decorators)、命名空間(Namespace)等面向對象編程(OOP)的概念。
對 TypeScript 不熟悉的讀者能夠參考碼之道公衆號以前的文章《爲何說 TypeScript 是開發大型前端項目的必備語言》,能夠關注 "碼之道" 公衆號(ID: codao)查看歷史文章。
正如 TypeScript 官網上所定義的,TypeScript 是 "Typed JavaScript at Any Scale"(任何規模的類型約束 JavaScript)。TypeScript 的主要特色就是類型系統,它經過加入類型來擴展 JavaScript。若是你瞭解靜態類型(Static Typing)和動態類型(Dynamic Typing)的區別,你應該會清楚靜態類型的優點:可預測性,健壯性,穩定性。經過編譯,TS 代碼能夠轉化爲原生的 JS 代碼,所以在瀏覽器兼容性上,TS 代碼沒有任何問題。
下面兩段段代碼能夠清楚的理解分別用 純 JS 和 TS 編寫前端應用的區別。首先看純 JS(沒有 TS)的樣例代碼。
// JS Example // 沒有任何類型定義 // 數據類型約束全靠文檔或記憶 // 合法用戶實例 const validUser = { name: 'Zhang San', sex: 'male', age: 40, }; // 非法用戶實例,編譯時不會報錯 const invalidUser: User = { sex: 'unknown', age: '10', }; console.log(invalidUser.name); // undefined console.log(invalidUser.name.substr(0, 10)); // Uncaught TypeError: Cannot read property 'substr' of undefined
能夠看到,整段代碼不會報語法錯誤(Syntax Error),所以能夠順利在 JS 引擎中運行。運行到 console.log(invalidUser.name)
時會打印 undefined
,一樣不會拋錯。不過這給後面的代碼帶來了隱患。當執行接下來的一句 console.log(invalidUser.name.substr(0, 10))
時,會報 Uncaught TypeError: Cannot read property 'substr' of undefined
這個在 JavaScript 中很是常見的錯誤。對於大型項目來講,一旦開發者遇到這樣的錯誤,一般是無從下手的,由於你不知道這個 undefined
是如何產生的:來自後臺 API、或來自前面的代碼邏輯錯誤、仍是數據問題?
再看看下一段 TS 的代碼。
// TS Example // 性別 type Sex = 'female' | 'male'; // 用戶類 interface User { name: string; sex: Sex; age: number; } // 合法用戶實例 const validUser: User = { name: 'Zhang San', sex: 'male', age: 40, }; // 非法用戶實例. 編譯報錯 const invalidUser: User = { sex: 'unknown', age: '10', }; console.log(invalidUser.name); // 編譯報錯 console.log(invalidUser.name.substr(0, 10)); // 編譯報錯
因爲用 type
和 interface
定義了類型,TS 編譯器能夠在預編譯的時候掃描代碼提早發現錯誤,例如缺乏字段或者字段非法等等。編譯這段代碼時,你會發現錯誤會在編譯時提早拋出來。所以開發者可以在運行代碼以前提早預警可能的 Bug,並對此採起措施。
TypeScript 幾乎是大型前端項目的標配,幾乎是每一個前端工程師的必備技能。
前端工程化相關的知識還有不少,前文只介紹了一些核心知識。其餘的一些前端工程相關的知識還包括但不限於如下內容:
本文從前端行業的發展開始,介紹了關於前端技術發展的歷史背景,解釋了前端工程化的重要性和必要性,並從打包部署開始,講解了現代化前端工程的打包部署過程以及實現工具。接下來,本文還介紹了前端工程化的另外一個重要概念,模塊化,解釋了隨着前端應用變複雜的趨勢,產生的模塊化的需求,以及如何實現模塊化。以後,還介紹了前端框架的發展,包括最初的 jQuery,和後來的 AngularJS,以及如今的 React、Vue、Angular 三大前端框架,還有將來的前端框架發展展望。除此以外,本文還介紹了組件化和類型約束,解釋了爲何要在大型項目中使用 TypeScript。
總之,前端行業是一個高速發展的行業,特別是最近幾年,互聯網的高速發展催生了前端工程的發展,讓前端工程師成爲名副其實的工程師崗位。前端工程師之因此能稱做工程師,毫不僅僅是由於他們能寫前端代碼,而是他們能利用架構思惟和工程化思惟來構建和管理大型複雜的前端應用,讓用戶能體驗到後臺功能複雜、但前臺使用簡單的各類 Web 或移動應用。前端技術以及前端工程化還在繼續發展,隨着新技術的出現和不斷成熟,相信咱們還會學習到更多有趣而實用的前端知識。今天入坑前端的你,還學得動麼?
若是您對筆者的文章感興趣,能夠加筆者微信 tikazyq1 並註明 "碼之道",筆者會將你拉入 "碼之道" 交流羣。