代码优化(实战)-如何写出强壮又优雅的代码?

🐯 前言

为啥写这篇文章?现在网上说的代码优化,大部分都是性能优化。前端业务代码大部分情况不需要考虑性能,个人觉得网上代码优化的文章并不实用。因此开此篇来论述我心中那像诗一样的代码。

🐯 啥是好代码?

网上的标准也很多,最核心最实用的那一条是:让人看得懂的代码!这是我个人多年实战+思考的答案。代码本身就是人与机器交互的工具,如果你的代码晦涩难,那肯定就是菜鸡代码,代码是给人看的而不是给机器看的,机器看的是二进制的10而不是代码。

下述的代码优化内容都是以《让人看得懂的代码》为核心。为啥我长篇大论《让人看得懂的》这个代码思路?因为现实中很多人写代码,从来没有思考过这个事情,写了好几年代码,一样菜得抠脚。写好代码核心是方向对,只要思想不滑坡,啥事都好说。愿各位的代码都能像诗一样优雅。
代码优化(实战)-如何写出强壮又优雅的代码?

优化一 : forEach乱用,API乱用

很久以前面试的时候,面试官提的一个问题:在用forEach的时候,如何跳出整个循环?我没答上,只记得需要用特殊的方式才能跳出forEach,后面回家查才知道是哪个方式。

当我责怪自己这么基础的都不知道,突然察觉不对,如果要跳出循环,为啥不用find或者some,为啥用forEach?forEach根本就不是干这个事的,我用forEach从来就没跳出过循环。是面试官傻逼,不是我傻逼。面试官他用forEach,但根本就没思考为啥用forEach。

写一篇文章,‘的’,‘得’,‘地’即使乱用,大部分人也都能理解文章的意思。就像我们代码的forEach,find,some,every乱用。但一篇流畅的文章,‘的地得’的使用必定是正确的。别人看你代码,看到forEach就是默认它是遍历完整个循环,结果你非要整活跳出forEach,别人不会觉得你牛逼,居然还能跳出forEach循环,只会觉得你是个憨,为啥要用这么变扭的方式,白白损害代码的阅读性。

api是一个英文单词,不是a1,a2,a3。每个api都是有自己的语义的,有自己的使命的。比如every,当遍历空数组时,返回的是true而是false。

let arr = []
const bolEvery = arr.every(item => item === 3)
const bolSome = arr.some(item => item === 3)
// bolEvery为true,而不是false。bolSome却为true。

因为every检测整个数组每一项是否都符合标准,空数组没有内容,所以属于都符合则返回true,这正好对应every的中文翻译:每个。而some的中文翻译是:某个,则检测整个数组某项是否都符合标准,只有有一项符合标准,就是true。而空数组,自然是false。

这个forEach的问题是个小问题,其实只是个引子,核心是代码思路。在用api前,先思考这个api到底是啥意思。每个api都用准确的代码,就像一篇用词精准的文章,能大大减轻代码的阅读难度。

写好一份vue或react代码,很多人把精力投入到了源码中,但把它的官方api文档重新看一次,收获或许更多。

优化二: 减少不必要的流程,降低代码复杂性

功能需求

一共三种状态,默认图片背景,自定义图片背景,自定义颜色背景。单选,只能有一种状态存在。
代码优化(实战)-如何写出强壮又优雅的代码?

原先的代码

// 操作类型  1 颜色 2 图片 3 默认图片
let dealType: Ref<number> = ref(1)
const listImg: any = ref([])
const clickReviewImage = (index, elIndex) => {
  dealType.value = 3
  name.value = listImg.value[index]?.[elIndex]?.diyImageInfoName
  norm.value.backgound = [
    {
      url: listImg.value[index]?.[elIndex]?.diyImageInfoUrl,
      height: 240
    }
  ]
}
const isShow = (index, elIndex) => {
  return status.value === 3 && listImg.value[index]?.[elIndex]?.diyImageInfoName === name.value
}
const deleteImage = () => {
  style.value.background = color.value
  status.value = dealType.value = 1
}

... 下面还有一堆代码

还有一堆代码省略了,都是围绕dealType状态更改的代码,大家就不用看了,因为我也没看,我直接重构了。需求明明不复杂,但能整得这么复杂,我也是醉了。

优化后的代码

  //1 颜色 
const color = ref('')
//2 图片 
const bg = ref('')
//3 默认图片
const defaultBg = ref('')
// 设置颜色
funtion setColor(value){
    color.value = value
    bg.value = ''
    defaultBg.value = ''
}

优化后就变得很简单很清晰了。之前他包多了一层,用状态去控制页面的展示内容,我直接把它状态那层中间商直接删了,逻辑立刻简化了。

这里并不是说,在页面增加一层状态管理是错的,在复杂情况时,增加一层状态管理可以使逻辑更加清晰,能大大提升代码阅读性。错的是乱加状态管理!

代码优化(实战)-如何写出强壮又优雅的代码?

什么时候加状态管理比较好?这问题很简单,视图内容复杂的时候。

举个例子:本来实现这个功能时,我是没有加状态的,和上面的优化后的例子一样,使用几个参数(比如isShow:是否显示占位图片)来控制视图,但发现需要控制的内容太多了,且几种参数也会有交集。因此马上改用状态管理,把页面的几种状态管理起来,再用状态去影响视图参数。大大增加的代码的可阅读性。

备注:使用状态管理时,注释一定要清晰,否则阅读性一样低,纯属挑水淋石头,无用功。

/** 当前template状态
  状态:   1.是容器但不能移动。
            当父级不是容器,自身是容器,就会这种状态。
          2.不是容器能移动
            普通组件状态。
          3.是容器也能移动
            父级是容器,本身也是容器。
            4.不能移动也不能当容器。(根节点下的内容,不能移动也不能当容器,暂时搁置先)
          备注:默认是普通组件(不是容器能移动),当父级不是容器时,子级都是不可移动的。
*/
let type: '1' | '2' | '3' = '2'
setType()
function setType() {
  const parentIsContainer = inject<any>('compParent');
  //若组件父级是容器,自身也是容器,则状态为3
  if (isContainer && parentIsContainer?.isContainer) {
    type = '3'
  }
  //若组件父级不是容器,自身也是容器,则状态为1 
  else if (isContainer) {
    type = '1'
  }
}

其实这个代码优化思路和第一个思路差别不大,万变不离其宗。就是写代码前,先思考,我写这一段代码的目的是啥?是否有用?带着思考去写代码,代码就会越来越优雅。

题外话

如果那个辛辛苦苦写了一堆代码,结果被我重构的前端,看到我的这篇文章,可能会觉得我纯属脱裤子放屁,多余。这里说说我的看法,没有人喜欢重构别人的代码,但遇到逻辑复杂的功能,菜鸡代码和优秀代码是天壤之别。

我重构他代码的原因,并非他代码写得水,而是因为这里的业务是要在两端共用的,他在这一端搞了个无用的状态管理,那在另外一端,也得加这一套东西,而两端的业务需求又是不太一样的,因此还得整两套逻辑去维护他的这个无用的状态管理。这TMD谁顶得住啊。他外包搞完这个项目就走了,后面全得我维护,我不重构,后面一堆摊子等着我。

在这里也求求一些写代码很随意的小伙伴,我也不想卷,但垃圾代码遇到复杂功能,绝对是噩梦中的噩梦,大家都是打工人,打工人何苦为难打工人。

另外说一句,上个前端小伙伴,你的代码是有点水,我重构你的一个功能,我能提出好几个代码点。。。下面的优化3和优化4,也都是重构他代码得到的。

优化三: 自动化导入,逻辑更加清晰

一些重复的批量导入,有api批量导入。这样逻辑清晰,活也少。

优化前

import default01 from '../../../imgs/inside/01.png'
import default02 from '../../../imgs/inside/02.png'
import default03 from '../../../imgs/inside/03.png'
import default04 from '../../../imgs/inside/04.png'
import default05 from '../../../imgs/inside/05.gif'
import default06 from '../../../imgs/inside/06.gif'
// 默认图片
const defaultImgList = [
  {
    name: '01.png',
    url: default01
  },
  {
    name: '02.png',
    url: default02
  },
  {
    name: '03.png',
    url: default03
  },
  ....省略代码

优化后

getLocalityImageList();
function getLocalityImageList() {
  const modulesFiles = import.meta.glob("../../../imgs/inside/*", {
    eager: true,
  }) as any;
  for (const path in modulesFiles) {
    const arr = path.split("/");
    defaultImgList.push({
      url: modulesFiles[path].default,
      name: arr[arr.length - 1],
    });
  }
}

优化思路

没啥思路,遇到批量导入的需求,就该这样做。批量导入,后期也好维护很多。就像上面的例子,如果文件夹里要新增一张图片,不用批量导入,那我还得手动去引入一张新的图片,这多傻啊。

优化四: 能集中管理的数据与方法,就尽量集中

我没搞懂上一个小伙伴为啥非要每个页面都重复同一个方法。且他写得还不好,我还得一个个页面去删他的代码,折磨。一样的方法,肯定放在一个地方管理,然后各个地方引用,即省事,维护性也高。

结束语

好的代码其实并不难,抓住一个核心点:《代码是写给人看的》。 只要思想不滑坡,代码就会越写越好。

代码优化的点,还有很多,有喜欢的小伙伴,帮忙点个赞,我下期再更。本来以为内容会很少,没想到写了快半天,2000多个字,看来我对垃圾代码的怨气还是蛮深的,哈哈哈哈,这不能怪我,谁也不喜欢重构别人的代码,重构代码,贼容易出事。

再次祝愿大家的代码像山一样强壮,像诗一样优雅。

原文链接:https://juejin.cn/post/7341304374756179995 作者:夏目友人爱吃豆腐

(1)
上一篇 2024年3月3日 上午10:32
下一篇 2024年3月3日 上午10:43

相关推荐

发表回复

登录后才能评论