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

🐯 前言

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

🐯 啥是好代码?

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

javascript 复制代码
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文档重新看一次,收获或许更多。

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

功能需求

一共三种状态,默认图片背景,自定义图片背景,自定义颜色背景。单选,只能有一种状态存在。

原先的代码

javascript 复制代码
// 操作类型  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状态更改的代码,大家就不用看了,因为我也没看,我直接重构了。需求明明不复杂,但能整得这么复杂,我也是醉了。

优化后的代码

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

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

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

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

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

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

javascript 复制代码
/** 当前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批量导入。这样逻辑清晰,活也少。

优化前

javascript 复制代码
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
  },
  ....省略代码

优化后

javascript 复制代码
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多个字,看来我对垃圾代码的怨气还是蛮深的,哈哈哈哈,这不能怪我,谁也不喜欢重构别人的代码,重构代码,贼容易出事。

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

相关推荐
拉不动的猪3 分钟前
前端常见数组分析
前端·javascript·面试
小吕学编程20 分钟前
ES练习册
java·前端·elasticsearch
Asthenia041227 分钟前
Netty编解码器详解与实战
前端
袁煦丞32 分钟前
每天省2小时!这个网盘神器让我告别云存储混乱(附内网穿透神操作)
前端·程序员·远程工作
一个专注写代码的程序媛2 小时前
vue组件间通信
前端·javascript·vue.js
一笑code2 小时前
美团社招一面
前端·javascript·vue.js
懒懒是个程序员2 小时前
layui时间范围
前端·javascript·layui
NoneCoder2 小时前
HTML响应式网页设计与跨平台适配
前端·html
凯哥19702 小时前
在 Uni-app 做的后台中使用 Howler.js 实现强大的音频播放功能
前端
烛阴2 小时前
面试必考!一招教你区分JavaScript静态函数和普通函数,快收藏!
前端·javascript