注册
web

【如诗般写代码】你甚至连注释都没玩明白

引言

要问我认为最难的事是什么,那只有维护前人的代码。
我经常能看见一个文件里,写上百行,没有几个函数,没有注释,没有换行,
一头扎进去,闷头写到天昏地暗的

什么修复bug,提升性能之类的都不是事,会用调试工具和分时渲染就够了
但是看屎山是真的难受


注释篇

  1. 利用注释在编辑器开启代码提示

    image.png

    看到区别了吗,左边用的是文档注释,鼠标悬浮能看到变量描述
    右边用的是行内注释,没有任何作用

    初步认识了文档注释的好处后,很多人可能还是不用,因为嫌麻烦。
    所以编辑器也为你着想了,以 VSCode为例,输入 /**,就会自动生成文档注释
    如果在函数上面,再按下回车,还能补齐函数参数文档,如下图所示

    comment.gif


  1. 利用文档注释描述函数功能

    当我鼠标悬浮在函数上时,就能看到他的各种描述,从其他文件导入也有效
    image.png


  1. 智能提示当前参数描述,以及类型等

    这里也能用快捷键呼出,详见我上篇文章:# 【最高效编码指南】也许你不会用VSCode | IDEA

    image.png


  1. 添加 JS 类型,实现类似 TS 的效果

    这里我呼出代码提示,但是他并没有给我补全任何方法,因为他不知道你的类型是什么

    image.png

    如果是强类型语言的话,那就会给你补全代码
    那么动态类型如何实现呢?以 JS 为例,使用文档注释即可,也就是前阵子沸沸扬扬的利用 JSDoc 代替 TS

    image.png

    不仅于此,连枚举都能实现,反正 TS 有的,他应该都有,我没有详细研究

    image.png

  2. 文档注释指令

    如下图所示,我想在文档注释里写上用法,但是他的格式十分丑陋,而且没有语法高亮

    image.png

    于是我使用 example 指令,告诉他这是一个示例,这时就有语法高亮了

    image.png

    指令还有很多,你们输入 @ 就会有提示了,比如 deprecated,标记已弃用
    这时你使用它就会有个提示,并且划上一根线

    image.png

  3. MarkDown 文档注释

    有时候,指令可能不够用,这时就可以使用 MarkDown 语法了

    image.png

  4. 结合 TS

    定义类型时,写上文档注释,当你鼠标悬浮时,就能查看对应注释

    image.png

    函数重载情况下,文档注释要写在类型上才行,下面这种无效

    image.png

    要写在类型定义的地方才行

    image.png

  5. 总结

    如果你用的是变量、函数或是 TS 定义类型,你要写注释,那就一定要写 文档注释,我跪下来求求你了 😭

减少条件分支语句

  1. 策略模式,写个映射表即可。这个有一点开发经验的应该都知道吧

    如果遇到复杂情况,映射表里也可以写函数,执行后返回逻辑

    image.png

  2. 提前返回

    这里第 2 种提前返回就减少了一层嵌套,实际开发中,能减少更多嵌套语句

    image.png

  3. 多个相等判断,使用数组代替

    image.png

代码七宗罪

让我来细数一下这坨代码的罪行,然后引出另一个主题,美化代码
下面这段,这简直是"甲级战犯",

  1. 一堆变量写了或者导入了不用,放那恶心谁呢
  2. 注释了的代码不删 (虽然可能有用,但是真丑)
  3. 都什么年代了,还在用var (坏处下面说)
  4. 用行内注释和没写区别不大,要写就写文档注释 (文档注释的优点上面解释了,不再赘述)
  5. 小学生流水账一般的代码,连个函数入口都没提供,想一句写一句
  6. 连个代码格式化都不会,多按几个回车,你的键盘不会烂掉;每个分段加个注释,你的速度慢不了多少
  7. 硬编码,所有类型用字符串直接区分,你万一要改怎么办?

image.png

语义化

我经常能看见一个文件里,写上百行,没有几个函数,没有注释,没有换行
一头扎进去,闷头写到天昏地暗的,比如下面这种

image.png

这玩意要我一行一行看?我是真的被恶心坏了
写代码要突出一个重点,看个大概,然后才能快速排查,看第三方库源码也是如此

我的习惯是写一个主入口,你叫 main | init | start 什么的都行,我只希望你能写上
然后主入口按照逻辑,给每个函数命名,这样一眼就能看出来你在干什么
如下图所示,这是我的偏好

image.png

我喜欢利用函数全局提升,把初始化函数放在文件顶部。这样每次打开一个文件,就能立刻看到大概逻辑
所以我很少用匿名函数,像上面那种全部写一坨,还都是匿名函数,我真的很难看出来谁是函数,谁是变量

这就引出一个新问题,函数的二义性

函数二义性

众所周知, JS 的类就是函数,里面有自己的 this,可以 new 一个函数

image.png

你要知道他是函数还是类,一般是通过首字母是否大写区分
但是这仅仅是弱规范,人家爱咋写咋写,所以后来出现了匿名函数(主要还是为了解决 this)

匿名函数没有自己的 this 指向,没有 arguments,如下图

image.png

而且用 const 定义,所以也就没了函数提升,严格来说,匿名函数才是真函数

不过我觉得直接写匿名函数有点丑,而且写起来似乎繁琐一点,虽然我都是用代码片段生成的
如果用了匿名函数,那么我就没了函数提升了

所以我仅仅在以下情况使用匿名函数

  1. 作为回调函数
  2. 不需要 this
  3. 函数重载

函数重载我来说说吧,应该挺多人不知道。
比如下图,针对每一种情况,写一遍类型,这样就能更加清楚描述函数的所有参数情况

image.png

不过这样好麻烦,而且好丑啊,于是可以用接口,这时你用 function 就实现不了了

image.png

var 的坏处

  1. var 会变量提升,你可能拿到 undefined

    image.png

  2. var 没有块级作用域,会导致变量共享

    按照常识,下面代码应该输出 0,1,2,3,4

    image.png

    但是你里面是异步打印,于是等你打印时,i 以及加了5次了,又没有块级作用域,所以你拿到的是同一个东西

    在古时候,是用立即执行函数解决的,如下图。因为函数会把变量存起来传给内部

    image.png

    现在用 let 就行了

    image.png

    所以我求求你别用 var 了

格式化

这里可能有争议性,仅仅是我个人喜欢,看着舒服

大多数写前端的,基本人手一个 Prettier 插件自动格式化,再来个 EsLint
然后也懒得看配置,默认就是 2 格缩进,回车多了会被删掉什么的

这样下来,整个文件就相当臃肿,密密麻麻的,我看着很难受

我的风格如下

  • 用 4 格缩进
  • 代码按照语义类型分块,写上块级文档注释
  • import 语句下面空两行,这样更加直观
  • 每一段,用独特醒目的文档注释划分
  • 定义变量优先使用 const,并且只写一个 const
  • 函数参数过长,则一行放一个参数
  • 写行内样式以及较长字符串时( 比如函数作为字符串 ),用特殊的宽松格式书写,保持类似代码的格式化
  • if 分支语句,要多空一行,看着清爽
  • 三目运算,用三行来写
  • 条件判断尽量提前 return,减少分支缩进

下面来用图演示一下,不然看着上面的描述抽象

代码按照语义类型分块,写上块级文档注释

每一段逻辑写完,用个醒目的、大块的文档注释分开。
全部执行的逻辑,放在一个 init 函数中

image.png

定义变量优先使用 const,并且只写一个 const

比如声明变量,我喜欢这么写
按照分类,类型不同则换行,并且写上注释,仅用一个 const

image.png

来看看大众写法,可以说 99.9878987%的人都这么写,这种我一看就难受

image.png

如果你用 let,并且用 4 格缩进,那么你就刚好对齐了,能少写一个回车
不过尽量使用 const

image.png

函数参数过长,则一行放一个参数

如果你这么写,那我看完会头晕眼花,属实是又臭又长的参数列表

image.png

如果你这么写,我会夸你代码和人一样好看

image.png

三目运算格式化

这俩,你说谁的可读性高,肯定是分三行写的好看啊

image.png

字符串以及对象格式化

这俩,你说谁看得舒服,那肯定是 2 啊
我看了身边的人和网上的很多代码,大多数都是 1 这种

image.png

不管你是用字符串,还是对象等方式表达,你都应该写 2 这种样式

image.png

分支语句

这俩哪种好看还用说吗,肯定是左边的好啊。但是你用 Prettier 格式化的话,应该就变成右边的了
同理 try catch 之类的也是一样

image.png

最后,多用换行,我跪下来求求你了 😭


作者:寅时码
来源:juejin.cn/post/7335277377621639219

0 个评论

要回复文章请先登录注册