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 并注明 "码之道",笔者会将你拉入 "码之道" 交流群。