最后
好了,这就是整理的前端从入门到放弃的学习笔记,还有很多没有整理到,我也算是边学边去整理,后续还会慢慢完善,这些相信够你学一阵子了。
做程序员,做前端工程师,真的是一个学习就会有回报的职业,不看出身高低,不看学历强弱,只要你的技术达到应有的水准,就能够得到对应的回报。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
学习从来没有一蹴而就,都是持之以恒的,正所谓活到老学到老,真正懂得学习的人,才不会被这个时代的洪流所淘汰。
placeholder=“Username” />
)}
Ant Design 组件库中已经提供个几乎所有的常见表单组件,如:Select 、Checkbox 、Radio 、Cascader 等,但在实际业务中,我们还是会需要设计业务相关的表单项,Form 表单通过统一组件接口的方式满足了这个技术需求,具体规约如下:
自定义或第三方的表单控件,也可以与 Form 组件一起使用。只要该组件遵循以下的约定:
-
提供受控属性 value 或其它与 valuePropName 的值同名的属性。
-
提供 onChange 事件或 trigger 的值同名的事件。
-
不能是函数式组件。
这正是“开闭原则”的一个典型实践案例,即表单核心逻辑(校验、提交等)保持不变并封装在 Form 组件中,自定义表单项只需要满足上述三条规约,就能平滑接入到 Form 组件中,和 Ant Design 原生组件契合在一起。
Ant Design 中的 Form 组件通过这样一个简洁的设计,完美提供了表单类型页面的统一解决方案。
函数式编程
随着人工智能、区块链、AR、VR、新零售等业务场景的出现,产品界面交互正在变得越来越复杂,这就对现代的前端开发者提出了更高的要求。如何快速、正确、高效地开发出高复杂度页面是目前前端技术最需要解决的问题。
函数式编程(以下简称 FP )凭借其高复用性、易测试性和与之带来的健壮性和简洁开始逐渐占据前端技术圈,我们发现越来越多的前端框架以 FP 为设计核心准则。
我们先简单介绍一下 FP,函数式编程的特征主要包括以下几个方面:
-
函数为“一等公民”
-
模块化、组合
-
引用透明避免状态改变
-
避免共享状态
JS 语言中的函数不同于 Java ,C/C++ 等语言, 可以被当做参数和返回值进行传递,因此天生具备“一等公民”特性。“模块化、组合”、“引用透明”、“避免状态改变”、“避免共享状态”这四个特征都需要通过特定代码模式实现。先举两个小例子:
找出字符串中率先出现的四个非数字字符?
非 FP 风格
var words = [], count = 0;var text = str.split(‘’);
for (var i = 0; couont < 4, i < text.length; i++) {
if(!text[i].match(/[0-9]/)) {
words = words.concat(text[i]);
count++;
}
}
FP 风格
var words = str.split(‘’).filter(function(x){
return (!x.match(/[1-9]+/))}).slice(0,4);
第二段代码中使用的 js 数组方法 filter 和 slice,去掉了 for 循环,代码更简洁流畅。在写具体业务代码的时候,“模块化、组合”是 FP 最常用的技术,也是最重要的实现功能的手段。
分别实现数组所有元素相加、相乘、相与?
非 FP 风格
function plus(array) {
var res = array[0];
for (let i = 1; i < array.length; i++) {
res += array[i];
}}function mul(array) {
var res = array[0];
for (let i = 1; i < array.length; i++) {
res *= array[i];
}}function and (array) {
var res = array[0];
for (let i = 1; i < array.length; i++) {
res = res & array[i];
}
}
plus(array);
mul(array);and(array);
FP 风格
var ops = {
“plus”: (x,y)=>x+y,
“mul” : (x,y)=>x*y,
“and” : (x,y)=>x&y
}
function operation(op, array) {
return array.slice(1).reduce(ops[op], array[0]);
}
operation(“plus”, array);
operation(“mul”, array);
operation(“and”, array);
后一段代码中,使用了 reduce 函数代替了 for 循环,并将数值计算部分作为模块提取出来,当有新的计算类型时,只需要在 ops 对象中定义计算过程。这里就体现了 FP 中“模块化、组合”的特性。在 FP 风格下,我们习惯将复杂逻辑切割成一个个小模块,通过组合这些模块实现新的业务功能,当有新的需求到来时,我们尽可能地复用已有模块达到目标。FP 代码在复用性方面相比 OOD 有明显的优势。
React 中的 FP 思想
React 框架中,当用户操作 UI 或者 API 的返回带来了数据的改变,React 随即进行 virtual dom diff 计算得到 dom 的修改指令,对 dom 元素应用修改指令便得到最新的 html 界面,如下图所示:
不难发现,React 其实是应用数据对UI的一种映射,不同的数据会映射出不同样式的 UI 界面,我们可以得出如下的表达式:
U I = R e a c t ( d a t a ) UI = React(data) UI=React(data)
没错,React 的本质其实是一种函数,并且还是符合 FP 要求的“引用透明”函数。所谓“引用透明”就是指函数的输出仅依赖函数参数,不受任何外部环境影响。这样的函数可测试性强,也非常容易进行组合。
在 React 的体系下,任何组件都可由一个个更小的组件构成,每个组件都只关心自己的输入,他们不断地接受新的数据并输出对应的新的UI界面。React 框架中常用的“高阶组件”可以看作引用透明”函数的组合模式。
在具体业务中我们通常还需要权衡 React 组件的复用性和开发体验,如果组件被拆分的过于细,固然复用性会提升,但文件数量会增加,对应的文档和沟通成本也会增加,这也是 FP 在实践过程中经常遭人诟病的点,即复用性提升后带来的额外开发成本。
消息机制
消息机制是软件工程中一个普遍运用的工程思想。“设计模式”中的观察者模式、Windows 操作系统底层、Spring 框架中的 ApplicationListener 模块、Objective-C 语言中的函数调用、都是通过消息机制驱动的。
使用消息机制最大的好处在于可以做到业务模块间安全解耦,模块间通过发送消息的方式进行协作,我们先举一个后端开发中的例子,下图是一个简单的预定系统的建模图,并没有使用消息机制:
在没有消息机制的情况下,用户模块需要知道订单模块的存在,并向起进行接口调用,同理订单模块需要向支付模块进行接口调用。这种设计下模块间是耦合的。
我们再来看一下使用消息机制的情况:
上图中,无论是客户下订单、支付还是预定都是通过消息的方式传递的,每个模块都是向一个消息处理器起发消息,同时也监听消息处理器发送回来的消息。在这种模式下,模块完全不知道其它模块的存在,彻底做到了解耦。
在前端业务开发中,我们经常也会用到 EventEmitter 库来进行消息传递。比如页面上有两块区域,一块用 React 框架渲染,一块用 D3 渲染的,当两块区域需要数据同步时,就可以使用消息机制进行通讯,保证页面数据整体一致。
如果你的业务中有不同生命周期的组件,建议采用消息机制进行管理,不仅消除了耦合,逻辑关系部分的代码也集中到了一个文件中,内聚性得到了提升。
使用消息机制的一个附属产物就是中间件,我们可以为消息定制各种中间件,在中间中完成一些通用逻辑,让业务代码更精炼。
说到前端框架中消息机制的运用,当然首推 Redux 框架,在 Redux 框架中,任何数据交互都需要先转化为一个 action,由 action 去触发 reducer 和相关的 middleware 处理 action,改变数据,最终同步到页面 UI 上,如下图所示:
关于使用 Redux 的种种利弊,在各大社区中都有很深入的讨论,本文不再赘述。
总结
“开闭原则”、“函数式编程”、“消息机制”这个三个软件工程中重要的思想方法好比三套内功口诀,掌握了他们,才能更深刻地理解技术框架本身,发挥出技术框架的最大威力。
写到这里突然又想起《天龙八部》中一段:
总结:
-
函数式编程其实是一种编程思想,它追求更细的粒度,将应用拆分成一组组极小的单元函数,组合调用操作数据流;
-
它提倡着 纯函数 / 函数复合 / 数据不可变, 谨慎对待函数内的 状态共享 / 依赖外部 / 副作用;
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
Tips:
其实我们很难也不需要在面试过程中去完美地阐述出整套思想,这里也只是浅尝辄止,一些个人理解而已。博主也是初级小菜鸟,停留在表面而已,只求对大家能有所帮助,轻喷🤣;
我个人觉得: 这些编程范式之间,其实并不矛盾,各有各的 优劣势。
理解和学习它们的理念与优势,合理地 设计融合,将优秀的软件编程思想用于提升我们应用;
所有设计思想,最终的目标一定是使我们的应用更加 解耦颗粒化、易拓展、易测试、高复用,开发更为高效和安全;