✨从代码复用讲起,专栏阶段性作结,聊聊?

2022-11-16 16:38:01 浏览数 (2)


本文为稀土掘金技术社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究!

专栏简介

作为一名 5 年经验的 JavaScript 技能拥有者,笔者时常在想,它的核心是什么?后来我确信答案是:闭包和异步。而函数式编程能完美串联了这两大核心,从高阶函数到函数组合;从无副作用到延迟处理;从函数响应式到事件流,从命令式风格到代码重用。所以,本专栏将从函数式编程角度来再看 JavaScript 精要,欢迎关注!传送门

回顾

前 6 篇传送门:

  1. ✨从历史讲起,JavaScript 基因里写着函数式编程
  2. ✨从柯里化讲起,一网打尽 JavaScript 重要的高阶函数
  3. ✨从纯函数讲起,一窥最深刻的函子 Monad
  4. ✨从延迟处理讲起,JavaScript 也能惰性编程?
  5. ✨从异步讲起,『函数』和『时间』该作何关系?
  6. ✨从响应式讲起,Observable:穿个马甲你就不认识啦?(附实战)

专栏至此,本篇算是阶段性作结了。

数据一览

专栏的点赞率相对于其它文章还算是比较高的。

只不过基础的阅读量偏低,几篇加起来还抵不了一篇口水文,原因可能有 3 点:

  1. 平台对新文章的推送策略从 9 月份之后发生变化,转变为更侧重于推送旧的好文章;
  2. 专栏内容相对较干,更多人来社区看文章或图一乐、或为解决问题、或为面试、或为收集好资源;
  3. 更文频率下降,导致账号整体流量偏小(因为同时段在关注另一件事);

在没什么宣传的前提下,专栏关注人数接近 100 人,还不错,感谢大家支持~

其实数据只是一方面,没必要唯数据论。

好的东西应该是经得起时间的检验,我自己都会经常回过头来看一看这些文章内容,说明用心写过,至少自己是认同的。即使不完美,也是现阶段的成果。完成总好过完不成,完成甚至大于拖延的完美。

事情是一点点去做、一点点去推动的,只要还没盖棺定论,就有持续改进、优化的机会和空间。如果逃避,就只能跟这事儿说拜拜了。。。关键也逃不掉,过一段时间又会遇到它,所以别畏惧,一句老话:不怕慢,就怕站。

不忘初心

不忘初心,那完成后的专栏内容和最初的专栏主题设计是否是贴合的呢?

最开始的设计是:

  1. 关注 JavaScript 两个核心 —— “闭包” 和 “异步”;
  2. 函数式编程真的串联了这两个核心吗?
  3. 从高阶函数到函数组合;
  4. 从无副作用到延迟处理;
  5. 从函数响应式到事件流;
  6. 谈代码重用;

一言以蔽之:从函数式编程角度来看 JS 闭包和异步。

实际上说的:

  1. 闭包的起源,闭包刻在 javaScript 基因里;
  2. 柯里化思想,一网打尽高阶函数;
  3. 纯函数、无副作用、函数组合、函数怎样“尽可能保持纯”;
  4. 延迟处理、JS 惰性编程,联系闭包和异步;
  5. 函数响应式编程 FRP, RxJS Observable 事件流及实战;
  6. 本篇后文将浅谈代码重用;

OK,方向好像确实是这么一个方向,没走偏。

可惜就是没有生产出一个好的轮子,可以直接供业务开发中使用。这感觉就像:我知道这东西很牛b,但是就还不能发挥出它十足的威力。

fine,理论指导实践,实践是检验真理的标准。所以这里是“阶段性”作结,

代码复用

Vue2 mixin

本瓜以前把 mixin 当个宝,在 Vue2 的大型项目中用起来,这复用、那复用,一段时间就发现不对劲了,这东西的覆盖规则怎么这么复杂,代码溯源怎么这么难呢?

这合并策略,是个人看了都会头疼吧?

  1. 如果是data函数的返回值对象 返回值对象默认情况下会进行合并; 如果data返回值对象的属性发生了冲突,那么会保留组件自身的数据;
  2. 如果是生命周期钩子函数 生命周期的钩子函数会被合并到数组中,都会被调用; mixin中的生命周期钩子函数会比组件中的生命周期钩子函数先执行(全局mixin先于局部mixin,局部mixin先于组件);
  3. 值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。 比如都有methods选项,并且都定义了方法,那么它们都会生效; 但是如果对象的key相同,那么会取组件对象的键值对;

看到这个合并策略真的会“谢”,去定位问题的时候,到处 debugger,看看到底是进的哪一个钩子函数中。

mixin 缺点:

  1. 变量来源不明确(隐式传入),不利于阅读,使代码变得难以维护。

组件里可以引入多个mixin,并直接隐式调用mixin里的变量/方法, 这会让我们有时候混乱 这些变量/方法 分别是哪个mixin里的?

  1. 多个mixins的生命周期会融合到一起运行,但是同名属性、同名方法无法融合,可能会导致冲突、很容易制造混乱。
  2. mixins和组件可能出现多对多的关系,复杂度较高(即一个组件可以引用多个mixins,一个mixins也可以被多个组件引用)。

狗都不爱。。。

这让人不禁联想到 JS 中同样让人头疼的东西,this 的绑定策略:

代码语言:javascript复制
情况 1. 默认绑定
情况 2. 隐式绑定
情况 3. 显示绑定
情况 4. new 绑定

具体就不展开了,也同样让人会“谢”。

this 的绑定其实也是为了代码重用,同样搞得人头疼。完全不符合 JS 轻量、简单的气质。

不过,代码写都屎山已经铸成,就不要轻易挪动了。。。

Vue3 Setup

后来大佬又带来了 Vue3 Composition API ,“好呀好呀"

用类似于react hook 式的函数式组件:

隐式输入、输出,变成了显示输入、输出,这不就是函数式编程思想中无副作用的纯函数一直要求的吗?

还问函数式编程的“无副作用”有什么实际的应用吗?

这个函数式组件,也就是相当于是一个闭包环境,内部变量不会影响外部变量,如果有命名冲突的情况,解构重新赋值即可。

这样看起来,就舒服多了~~

与其说,Vue3 模仿 React hooks,不妨说它们都只是按照函数式编程的思路在演进罢了。

React class

React 也是啊。React V16.8 hooks 出来之前的 class 组件,this 的绑定之麻烦,定位问题查询起来之麻烦,也是 this 的指向规则、以及隐式的输入、输出导致的。

比如:某个组件从 3 个以上的高阶组件去复用逻辑。

代码语言:javascript复制
this.props.xxx();
this.props.aaa();
this.props.bbb();

如果xxx出现了问题,如果对项目不熟悉的人的话想要找这个方法,就要分别去这三个高阶组件里面去找,或者去父组件里面去找。

React hooks

有了 hooks 的设计,

代码语言:javascript复制
const { xxx } = useXXX();
const { aaa } = useAAA();
const { bbb } = useBBB();

哪个有问题,就去对应的位置找哪个,显示输出,就是能轻松定位来源。

写法上,也更加简便、直观了:

class Component:

代码语言:javascript复制
class ExampleOfClass extends Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 1
    }
  }
  handleClick = () => {
    let { count } = this.state
    this.setState({
      count: count 1
    })
  }
  render() {
    const { count } = this.state
    return (
      <div>
        <p>you click { count }</p>
        <button onClick={this.handleClick}>点击</button>
      </div>
    )
  }
}

hooks:

https://code.juejin.cn/pen/7162070517803909120

小结

从 Vue2 mixin 到 Vue3 Composition API;从 react class 组件到 react hooks;

不用说,你都能感受到:

  1. 我们确实不喜欢隐式的输入、输出,对于代码的可读性太不又好了;
  2. 我们在复用的时候讨厌 this 指来指去;
  3. 千万不要在查找属性的时候,又要查同级的组件、父组件、父父组件,从哪来、到哪去,一定给说明白了。

复用思考

react 相对于 vue2 本身就是比较偏“函数式”的。

除了推崇显示输入、输出,即“无副作用”的写法;

它还推崇“值的不变性”。值的不变性就为了消除“状态”,函数式编程就强调“无状态”。

在大型项目中,每当声明一个新的变量,在多处去维护这个状态,这一定是一件容易导致混乱的事情。

再加上时间上的异步,乱上加乱,一层层去修改、覆盖值,刷新再刷新,很难再看清值变化的逻辑,还更加消耗性能。

函数式就有这个好:

用函数去运算值,而不更改值,函数组合就是值发生变化的过程。

函数式,再加响应式,消除时间状态,用事件流表达,极少的代码量就能实现复杂的功能。

只是,比如像 RxJS ,它的操作符比较复杂。可是像 React 的自定义 hooks 这种一样也是自定义方法,难道直接用不香?

可能二者并不矛盾,只是在往同样一个方向前进,其间有不同的表现。

说了这么多,归结一句话:

想要优雅的复用代码,务必学习函数式编程思想。你可能已经在用它了,而不自知。

专栏总结

突然,感觉没有太多想说的了,DDDD,借用延迟处理的思想:现在不想说,等想说的时候再说吧~~~

OK,以上便是本篇分享,专栏第 7 篇,希望各位工友喜欢~ 欢迎点赞、收藏、评论

0 人点赞