链接: pan.baidu.com/s/1_76lIW6L… 提取码: 6zf2
作者-\/ 307570512
接触 Node.js
当我正在愉快地设计着 WordPress 的自定义主题时,偶然间我在某前端网站上了解到了一个新的技术 —— Node.js。与它的相遇改变了我以后的学习路径,影响至今。
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(8124, "127.0.0.1");
console.log('Server running at http://127.0.0.1:8124/');
框架时代
当我在做 WordPress 主题的时候,绝大部分的主题开发者都会在前端做一些简单的效果,甚至有甚者会通过 JavaScript 实现一些原本只能通过后端来完成的事情,比如文章列表、文章内容的加载和渲染。而当年这些主题开发者基本上都会使用 jQuery 来进行这些 JavaScript 的操作,因为纯手写 JavaScript 在当时来说非常的繁琐(ES4时代,很多现在被广泛使用的原生 API 都仍未具备)所以当时 jQuery 就是大家的首选方案。
React:引入函数式编程(Functional Programming)的概念,使得写代码的思路更加严谨,更具有可维护性和逻辑可导性;
Vue:将 MVVM 模式变得非常简单易于入手,把 Progressive JavaScript Framework 的定位实践得非常到位。且如今 Vue 3.0 的 Composition API 更是在某种程度上将 Hooks 的玩法实现得比 React Hooks 更优;
结论:请不要害怕学习!不要惧怕新技术!
工程之路
虽然我在接触了框架和 Node.js 之后,发现 JavaScript 除了能实现一般只用于展示内容和呈现简单交互以外还能做更多的事情。但本质上还是围绕着多个页面进行页面上 DOM 元素的控制,而直到我打开了 Google 的一些网站时,我才发现原来网站除了能叫页面以外,还能称之为“应用”。
自从 Google 上线了一个完全不需要刷新页面就能完成所有事情而且体验很不错的 GMail 之后,我们发现网页原来也是可以承载那么复杂的逻辑和应用场景的。大家的热情异常地高涨,想着能不能让自己所负责的项目也有这么厉害高级的样子。但随着项目不断地复杂,代码规模也变得非常难以管理,而这个时候就需要工程化的引入。 工程化协作
对于企业来说除了研发效率要足够高以外,研发链路的安全、合规也是同样重要的。
什么叫安全合规?可管理的代码版本、可控制的发布流程、可管控的灰度机制,都是大厂用于保证项目流程稳定进行的必要工具。
有很多初学者或者还没有大公司经验的同学在写项目时都是单打独斗的,但更多的一线项目都需要至少 2~3 个甚至更多的人员一同参与开发的。
而这种时候,因为每个人的水平和开发习惯都是不一致的,而这些不一致就直接导致整体研发效率和项目进度受到极大的影响。所以就需要一种能够让大家在一个水平线上进行开发的模式,工程化需求便应运而生。
版本控制
Git:GitHub、GitLab、Coding…… SVN:BitBucket、Google Code…… 代码样式检查工具 JavaScript/TypeScript:ESLint
测试工具
单元测试:Karma、Jest、Mocha…… 持续集成:CI …… ▐ 工程化开发工具
从直接将 JavaScript 代码用 script 标签,到需要将 jQuery 文件和主要程序文件分别引入,再到 Node.js 出现后使用 npm 进行依赖库管理并使用 webpack 进行打包和压缩。工程类工具的发展见证着前端工程近十年的发展历史,对目前我们所常用的工程工具有更好的了解和实践,绝对是通往优秀路上不可或缺的一步。
依赖包管理工具:npm、yarn 打包工具:webpack、rollup 脚手架工具:create-react-app…… ▐ 工程化开发语言
相信很多同学都听说过 JavaScript 诞生之初的一些轶事,比如根本没有特别多的严谨思考,或者在非常多的场景中十分地晦涩,比如隐性转换等。
有人认为 JavaScript 能发展到如今的地位跟它的这种“灵活度”或者“松散度”有关联,虽然在某种程度上确实因为这种特性造成的 JavaScript 学习门槛比较低而间接导致。但就如我上面所说,当项目规模和人员规模不断发展乃至膨胀过后,这些特性会逐渐表现出来非常糟糕的体验:
团队之间因为没有良好的技术文档沉淀,信息不对等的情况直接导致代码在没有良好的单元测试时出现逻辑冲突;
第三方依赖库的 API 在设计上大量使用了 JavaScript 松散的特性,导致使用方在引用时频繁出现“迷惑”的状态;
当需要使用 JavaScript 与其他语言(特别是强类型语言)进行交互时,JS 过于松散的习惯会让对接方感到非常迷惑,对于双方的实际接入成本会比前期预估的大得多;
为了解决这种情况,来自不同编程领域的大牛们都纷纷开始想办法,于是乎便诞生了非常多的“轮子”:
Java 系:Scala.js、ClojureScript Go 系:GopherJS Microsoft:TypeScript Facebook:Flow、Reason 目前 TypeScript 已经影响了前端乃至整个 Web 领域的开发生态,TypeScript 之父 Anders Hejlsberg 创造过 Turbo Pascal、Delphi、C# 等在整个计算机科学领域都举足轻重的语言,而 TypeScript 又再次创造出翻天覆地的变化:
强类型的引入能让我们在写代码的时候从值优先的思维转变成类型优先;
强类型的引入能帮助开发工具(IDE 等)更好地为开发者提供便利性能力,如智能补全、类型检测、编译时检查等等;
TypeScript 可以让 JavaScript 更好地与其他语言进行交互,甚至转换为其他语言;
▐ 工程化通用组件
当需求不断变多后,“爱偷懒”的工程师们就会把经常用到的内容进行抽象,比如从很早以前就有的 ExtJS、Twitter 工程师发布的 Bootstrap 再到今天的 Ant Design、Element UI 等,都帮助我们更快更好更稳定地完成一些通用页面能力的开发。
React:Ant Design、Fusion Design Vue:Element UI、iView、Ant Design of Vue
逻辑抽象能力
随着我对 JavaScript 应用的编写经验不断增加,我所尝试的技术和场景也在不断地变得更加复杂。而当逻辑代码变得越来越复杂时我也渐渐发现一个新的问题,很多时候我所编写的逻辑代码是相似的,但相似之余其中的一些细节不尽相同,而这些代码往往是后期维护成本最高的。
export default {
beastBuff: (state) => {
let arr = [];
if (state.raceCount[0]['beast'] == 2 || state.raceCount[0]['beast'] == 3) {
console.log(`you got 2 beast`)
arr.push(state.racebuffdata[8])
} else if (state.raceCount[0]['beast'] == 4 || state.raceCount[0]['beast'] == 5) {
console.log(`you got 4 beast`)
arr.pop()
arr.push(state.racebuffdata[9])
} else if (state.raceCount[0]['beast'] == 6) {
console.log(`you got 6 beast`)
arr.pop()
arr.push(state.racebuffdata[10])
} else if (state.raceCount[0]['beast'] < 2 && arr.length == 1) {
arr.pop()
}
return arr;
},
caveclanBuff: (state) => {
let arr = [];
if (state.raceCount[1]['caveclan'] == 2 || state.raceCount[1]['caveclan'] == 3) {
console.log(`you got 2 caveclan`)
arr.push(state.racebuffdata[11])
} else if (state.raceCount[1]['caveclan'] == 4) {
console.log(`you got 4 caveclan`)
arr.pop()
arr.push(state.racebuffdata[12])
} else if (state.raceCount[1]['caveclan'] < 2 && arr.length == 1) {
arr.pop()
}
return arr;
},
demonBuff: (state) => {
let arr = [];
if (state.raceCount[2]['demon'] == 1) {
console.log(`you got 1 demon`)
arr.push(state.racebuffdata[5])
} else if (state.raceCount[2]['demon'] < 1 && arr.length == 1) {
arr.pop()
}
return arr;
}
// ...
}
我们不难发现这几个 xxxBuff 函数中的逻辑都非常接近,但也各有不同。那么如何能将这段代码进行优化和抽象呢?我当时给 TA 提出了一份示例代码:
const beastConfig = [ [2, [2, 3], 8],
[4, [4, 5], 9],
[6, [6], 10],
[2]
]
更高层次的思考能力
随着我对不同业务、不同场景和不同代码难度的不断探索和研究,我发现在前端领域乃至整个编程领域里,不同的框架和架构层出不穷地发展,其实在根本上就是各种实际业务场景在寻找更合适的 Better Practice(更好实践)。就如前面的所说的那样,不同的框架作者在开发的时候会采取不同的代码结构甚至代码哲学,这些不同的思维角度可能在框架的源码中并不会直接表现出来。但我不会说研读源码完全没有用!因为研读源码最起码可以学习其中的一些 trick 或者代码习惯。