21

系统性学习前端

 3 years ago
source link: https://zhuanlan.zhihu.com/p/267187829
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

引言

有些人说前端入门容易,尤其现在配套工程齐全、组件化程度高,运行几行命令,改动一些代码,就可以实现一些需求。但知识点多,新概念层出不穷,既有深度又有广度的话,非常考验能力。

在编程本质中,有二个非常有名的表达式:

  • 算法(Algorithms) + 数据结构(Data Structures) = 程序(Programs)
  • 逻辑(Logic)+ 控制(Control)= 算法(Algorithm)

前者大家听的很多,后者是由 Robert Kowalski 在一篇论文中提到:

任何算法都会有两个部分,一个是 Logic 部分,这是用来解决实际问题的。另一个是 Control 部分,这是用来决定用什么策略来解决问题。Logic 部分是真正意义上的解决问题的算法,而 Control 部分只是影响解决这个问题的效率。程序运行的效率问题和程序的逻辑其实是没有关系的。我们认为,如果将 Logic 和 Control 部分有效地分开,那么代码就会变得更容易改进和维护。

前端也有个很有名的表达式: UI = f(state)

IRva6nn.jpg!mobile UI = f(state)

这些简洁的公式,都已经是对基础和原理进行了多层的抽象。在实际的项目中,如果你不知道背后的基础和原理、没有自己的思考和理解,是不会有很深刻的理解的。

学习就是在自己的领域内一定程度的探索其基础和原理,你知道的越多,越感到自己不知道的越多,于是你就想了解的更多,形成一种螺旋式上升的过程,熟能生巧,巧能生通。

无论干哪一行,想要胜任愉快,离不开 4 样东西:才能、兴趣、方法和努力。没有才能则难以胜任,没有兴趣则难以愉快,没有方法则事倍功半,没有努力则一事无成。

要抓住一些不变的东西,更能让你在快速更新迭代中保持竞争力,遇到新的东西能更快融会贯通。因为本质的东西几乎是不变,从计算机被发明到现在本质运行还是 0 和 1 ,或是量子计算机能突破 0 和 1 的限制,本质一旦被建立,就会非常稳固,在这基础上就能构建各种丰富东西。

前端学习

前端工程师,前提是一名工程师,了解计算机的一些基本知识。然后作为 Web 前端工程师,所需要了解的大致可分为:

  • 编程语言
  • 现代浏览器的工作原理和 API
  • 跨平台
  • Node.js/前端工程化
  • 细分领域

编程语言

不管什么端,编程语言永远是工程师的核心利器。HTML/CSS/JS 作为 Web 前端三驾马车,重要性不明自言。如果语言发展的好,语言规范必然一直更新迭代,增加新特性。系统的阅读图书和文档,花时间,可以快速熟练的应用起来,但一些很深刻的东西,你可能需要在实际编程中不断学习。

掌握语言的使用最基本,深入理解,从术至道,就需要更深刻的基础理论作为支撑。 编程范式作为一门语言的基本风格或典范模式,是一门语言的世界观和方法论 。常见的编程范式有:命令式编程、声明式编程和面向对象编程,我们谈论多的函数式编程属于声明式的一种。一种范式可以在不同的语言中实现,一种语言也可以同时支持多种范式,JS 就是一种多范式的语言。

命令式编程( imperative programming ),其核心是:程序是由若干指令组成的有序列表,依次执行;用变量来存储数据,用语句来执行指令。下面 JS 代码的风格就是命令式编程:

// 求连续自然数的平方和
function sumOfSquares(nums) {
  let sum = 0, squares = [];
  for (let i = 0; i < nums.length; i++) {
    squares.push(nums[i]*nums[i]);
  }

  for (let j = 0; j < squares.length; j++) {
    sum += squares[j];
  }

  return sum;
}

console.log(sumOfSquares([1, 2, 3, 4, 5]));

声明式编程(declarative programming ),其核心是:对一系列行为进行有序陈述,强调做什么,而非怎么做,不提供细节的执行。下面 JS 代码相比于上面的代码就是函数式编程:

// 求连续自然数的平方和
function sumOfSquares(nums) {
  return nums
    .map(num => num * num)
    .reduce((start, num) => start + num, 0)
  ;
}

console.log(sumOfSquares([1, 2, 3, 4, 5]));

在以交互、事件驱动的 Web 应用,其实充斥了命令式范式。无可厚非计算机语言就是在命令式的基础上发展起来的,JS 虽然做为一门面向对象编程语言,和 Java、C# 等的面向对象编程的语言不同处太多。JS 的继承是通过原型( prototype )机制来实现,数据类型更是弱类型,动态类型的。但这不排斥 JS 保持开放和包容的心态采用不同范式的写法,取长补短。

相比编程范式,设计模式则类似战术,把一些经常出现的问题提出行之有效的设计解决方案,无关于什么语言。常见的设计模式则有工厂模式、单例模式、适配器模式、装饰器模式、代理模式、享元模式、策略模式、观察者模式、迭代器模式。

TS 是 JS 的超集,让 JS 具有了不同编程范式的优点,比如泛型、强类型等,使 JS 能适应越加复杂的现代 Web 应用,加上 ES 规范的不断迭代,JS/TS 是在不断进化。

Angular/Vue/React 作为 JS 的框架/库。Angular 完全拥抱 TS ,结合面向对象和函数式的优点,大而全,处处都为你考虑到了。Vue 和 React 则在拥抱函数式的同时在 Mutable 和 Immutable 中都有各自的建树。(Mutable 和 Immutable的概念简单的可以看这里: https://www. digitalocean.com/commun ity/tutorials/js-mutability )如果项目中使用比较多的框架,适当了解框架中的一些设计原理,有助于写出好的代码。

Web Assembly 让其他语言编译为二进制代码可直接运行在浏览器上,这极大提高了前端的性能和扩展可以使用其他语言的新特性,特别在计算量大和性能要求高的场景还是很有用处的。

前后端编程虽然差异不小,但接触不同的范式和不同的编程语言,对学习能力的提高有益无害。Stay hungry. Stay foolish.

现代浏览器的工作原理和 API

前端应用代码运行在浏览器上,对浏览器的了解,前端进阶所必须的。

现代浏览器发展到现在极度复杂,而且 Chrome 版本更新迭代飞快,源码大小都达到了 15 GB。介绍浏览器原理的文章虽然已经很图文并茂,但也是覆盖掉了很多细节,实际情况肯定复杂更多。况且大部分文章都有时效性,现在的实现可能已经有更好的方案。

下面的文章是发布在 Google 开发者网站上,应该是介绍现代浏览器内部最详细的文章了:

https:// developers.google.com/w eb/updates/2018/09/inside-browser-part1

相对于前端,了解浏览器的大致原理,工作上的帮助不是很直接,但这其实就是不变或变化慢的部分,理解底层的部分,对你构建上层知识的体系有着质的帮助。至少大致的了解浏览器怎么把一个 URL 变成一个可以交互的页面的。

浏览器怎么把 URL 变为一个网页的大致过程:

  • DNS 解析
  • 通过 HTTP/HTTPS 向服务器请求到页面
  • 解析 HTML 构建 DOM 树/计算CSS
  • 排版、渲染、合成
  • 绘制到屏幕上

JS 运行是单线程的,但浏览器执行 JS 代码是异步非阻塞的,所以才会有 Event Loop(事件循环)机制来确保异步代码同步代码事件等的执行顺序。Event Loop 其实也有规范,在 WHATWG 下的 https:// html.spec.whatwg.org/# event-loops ,所以跟着规范来理解,其实是最好的。

https:// yu-jack.github.io/2020/ 02/03/javascript-runtime-event-loop-browser/

JavaScript 中的对象一般分为二类:

  • 宿主对象(host Objects):由 JavaScript 宿主环境提供的对象。比如浏览器、Node.js。
  • 内置对象(Built-in Objects):由 JavaScript 语言提供的对象。浏览器根据标准规范来实现的。

浏览器环境的 API 其实非常繁杂,操作 CSS 和 DOM 的一些浏览器提供的 API 我们可能很熟悉,但是更多的 API 来自不同的规范标准比如 ECMA、WHATWG、W3C 等,还有些 API 根本没有被标准化。推荐在实际工作需要中如果碰到需要用到的 API 再去深入学习。

跨平台

大前端大致包含:

  • PC 端(浏览器)
  • 移动端(Android、iOS、Watch、小程序、H5)

技术和资本一样,都是追逐着成本降低的。如果有方案可以用 一套代码适配多个平台 的话,增加业务代码复用率、降低开发成本,趋势肯定往这方向发展。从一开始的 Cordova/phoneGap/Ionic,到 React Native/Weex,到 Flutter、小程序、PWA。

各方案体验不断的在提高,这是因为技术方案越来越向底层进行改造。下面四张图分别描述了不同方案 App 代码和平台之间的关联。

ARjyAbz.jpg!mobileq2aEf2R.jpg!mobileMZ7VnuI.jpg!mobileNFFZv2Y.jpg!mobile

使用 Native 性能和体验最好。

WebView 因为需要遵守通用的 Web 规范,实现的复杂度高,又缺乏直接调用系统 Services 的能力,所以性能和体验一直不佳。

React Native 则抛弃了 WebView,使用 JS 制定自己的开发规范,自己实现 Bridge 层调用原生 Widgets 和系统 Services。

Flutter 则更激进,抛弃了 JS 语言和系统原生 Widgets ,完全调用平台底层能力自己实现了一套 Widgets ,在性能和体验上其实更趋向于原生应用。

PWA 则本质还是 Web 的,依赖于 Web 标准的发展和 WebView 的发展。

按照现在各方案的势头,Flutter 最火,但是 Web 下的 Hybrid 和 PWA 还是很有机会,像极了战国时期各国的纷争,但谁又会是秦国。

Node.js/前端工程化

随着前端复杂度提高,前端工程化自然而然发展起来。Node.js 极大推进了前端工程化。包括 Docker、BFF 概念、Serverless,让前端触手其实伸向了后端。

工程化包含的东西太多主要分为:

  • 开发规范
  • 框架/模块化/组件化
  • 开发流程/工具
  • 构建/部署/发布
  • 统计/监控

开发规范的目的是在团队中统一项目的编码规范,便于团队协作和代码维护 。各团队需要根据自身的情况制定开发规范,并且需要通过工具在编码阶段或代码提交阶段根据 eslint 等工具快速提示开发者采取正确的编码规范。

现代前端项目已经都使用 ES Module 来作为模块化,组件化的思想在前端三大框架中体现很多,包括 Web Components 标准。复杂的应用中会需要数据流管理,或使用独立的数据流管理框架,或使用框架推荐的规范方式。更复杂的项目或有特殊需求的一些页面则会使用 前端微服务框架 ,国内比较火的则是蚂蚁开源的 qiankun 。

开发调试主流就是使用 Webpack 在本地开启服务,提供代理、热加载等一系列功能,代码的修改实时的反馈在浏览器上,并且不同框架也提供了浏览器 Developer Tools 插件,更方便查看组件的嵌套结构和数据分析。

构建/部署/发布则会集成 CI/CD ,然后集成进每个公司各自的发布流程中。具体可以在我另外一篇文章中了解更多。

whilefor:前端工程化:构建、部署、灰度 zhuanlan.zhihu.com VJ3Az2.jpg!mobile

通过在浏览器端,需要把用户行为的数据和前端错误日志上报,来分析用户和定位用户发生的报错信息,这二个方面的需求,虽然不是必要,但也算有价值,开源中比较有名的则是 Sentry 和 Matomo 。

细分领域

可视化

可视化是将数据组织成易于为人所理解和认知的结构,然后用图形的方式形象地呈现出来的理论、方法和技术。

简单点描述就是,将数据信息有效的组织起来,以图形的方式呈现出来。我们接触比较多的就是使用图表库来绘制大量的图表,比如 EChats 等,但可视化远远比这个复杂。

可视化相比于一般通用意义上的 Web 前端,在 数学/图形学、图形(SVG、Canvas、WebGL)/图形库工具(D3.js、ThressJS 等)、数据处理/分析、性能优化 这些领域上需要有更加深入的研究。

VrEZBrn.jpg!mobile

富文本编辑器/WebIDE

一个功能齐全的 Web 富文本编辑器的复杂度是非常非常高的。比如语雀、谷歌文档等,富文本编辑器都是这些产品的核心,需要有无数的细节处理。因为开发成本太大,所以如果产品中需要有富文本编辑器并且需要比较多的定制化,大多想到的是使用开源的产品上进行定制化的开发,如 Draft.js 、 Slatejs 。

VS Code 是使用 Electron 开发的,也就是 Web 那一套,所以证明在 Web 上实现体验流畅的 IDE 是可行的。WebIDE 远不止把 IDE 从本地搬到了浏览器上,必定需要集成一套开发流程和云端环境,代码的编译/运行/调试都在云端进行,开发者只需要一个浏览器就可以开发,未来可期。

搭建系统

Pro-Code、Low-Code、No-Code 前端对解放生产力、提高效率的追求永不停止。可视化搭建系统,能在中后台领域抽象出经典的场景、组件、数据流等,这个是很能提高效率的。但是没有银弹,只能在特定的领域中发挥作用。

智能化

最近出现很多前端智能化的声音。比如根据机器学习来让系统自动切图等,但感觉生搬硬套,非要使用机器学习那一套提高前端效率生产力,前端工程化/自动化那一套我们还没玩的炉火纯青,步子大了可能容易扯着蛋。

系统性学习

知识点实在太多,如果没有一个系统框架的学习方法,填鸭式的不断学习零散的知识点,太容易迷失了。

DIKW 模型

在知识管理领域的理论中,有一个 DIKW 模型,这套理论可以实践在你的任何学习的地方。它代表了知识管理的四个层级,也是学习的四个层次,分别是:Data(数据),Information(信息),Knowledge(知识),以及 Wisdom(智慧)。

把这套理论放置到编程语言的学习中。举例:

起初你没接触过任何编程语言时,你看到 let、var、for、while 等这些关键字时,你只知道他是英文单词,完全不知道他在编程语言中的意义,不知道他能干什么,这时候,它对你来说,就只是 Data 。

当你学习了所有的 JS 的语法,看到 let、if else、for 等就马上能知道这是什么意思,它在 JS 中能用来做什么,这时候它就从 Data 变成了 Information。每当你新学了一个语法或者一个API 使用,一些单词或者符号就会从 Data 变成 Information。

当你看到下面的代码,知道 b = a 只是将 a 的引用地址赋值给 b ,a 和 b 都指向了一个对象,知道值类型和引用类型在堆和栈中是以怎么样的形式存在的。这就是 Knowledge(知识)。

let a = { t1: 5, t2: 9 }
let b = a;
b.t1 = 6
delete b.t2;
b.t3 = 8 
console.log(a) // {t1: 6, t3: 8}
console.log(a === b) // true

如果你看到一个业务场景,根据现有的信息,从前端到服务端的情况都会有自己的判断,对技术选型、工程化,是否适合 Serverless、加入 BFF、Docker 等等都在脑海中可以浮现出来,看业务场景选择合适的编程范式提高效率等等。从细节到全局的把控都有一个自己的认知,知其然,还知其所以然。这时,这整套东西就是你的 Wisdom(智慧)。

INK-P 管理法

这是我在一个公众号上看到管理知识方面的方法,我把它应用到学习的实践中。在笔记软件里建立 4 个笔记本,分别叫 Inbox、Note、Knowledge 和 Project。

可以使用 Notion,配合 Chrome 插件。

  1. 阅读清单。

1)Inbox:存放一切收集到的内容

2)Note:存放已经完善好的信息,以备日后使用

3)Knowledge:存放按照主题组织起来的索引

4)Project:存放项目的必要信息

把你每天看到的需要看完或者需要做笔记没有完成的文章放到【阅读清单】中,几天或者每周来清理这些文章,阅读完把他们标记为已读。

如果发现有意义或者你想深入的主题,把这个主题放到 【 Inbox 】中,【Inbox】中存放你觉得有意义的主题。

待补充完善之后放入到 【Note】中,【Note】应该是比较稳定的一个主题的内容,但不是不变的,之后有更新,继续更新到这个主题之中。

【Knowledge】其实就是对主题做的索引,因为 知识点其实不是树状的,它是网状的,很多的知识点都会有关联。

yeQRV3M.jpg!mobile

结束语

上面的知识点,都只是很粗的提了一下,肯定有遗漏的点,不可能只看一篇文章,就事无巨细的了解了前端的方方面面,我和大家一样也在不断的学习中,在遇到不懂的知识点时候,官网文档、书、谷歌、付费知识等都是你的学习渠道,你需要主动的去求知,把所有的点花时间产生个 熵减 的过程,慢慢的构建自己的知识架构。

参考文献

扫码关注公众号


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK