引言
要问我认为最难的事是什么,那只有维护前人的代码。
我经常能看见一个文件里,写上百行,没有几个函数,没有注释,没有换行,
一头扎进去,闷头写到天昏地暗的
什么修复bug
,提升性能之类的都不是事,会用调试工具和分时渲染就够了
注释篇
-
利用注释在编辑器开启代码提示
看到区别了吗,左边用的是文档注释 ,鼠标悬浮能看到变量描述
右边用的是行内注释,没有任何作用
初步认识了文档注释的好处后,很多人可能还是不用,因为嫌麻烦。
所以编辑器也为你着想了,以 VSCode 为例,输入
/**
,就会自动生成文档注释如果在函数上面,再按下回车,还能补齐函数参数文档,如下图所示
-
利用文档注释描述函数功能
当我鼠标悬浮在函数上时,就能看到他的各种描述,从其他文件导入也有效
-
智能提示当前参数描述,以及类型等
这里也能用快捷键呼出,详见我上篇文章:# 【最高效编码指南】也许你不会用VSCode | IDEA
-
添加 JS 类型,实现类似 TS 的效果
这里我呼出代码提示,但是他并没有给我补全任何方法,因为他不知道你的类型是什么
如果是强类型语言的话,那就会给你补全代码
那么动态类型如何实现呢?以 JS 为例,使用文档注释 即可,也就是前阵子沸沸扬扬的利用 JSDoc 代替 TS
不仅于此,连枚举都能实现,反正 TS 有的,他应该都有,我没有详细研究
-
文档注释指令
如下图所示,我想在文档注释里写上用法,但是他的格式十分丑陋,而且没有语法高亮
于是我使用 example 指令,告诉他这是一个示例,这时就有语法高亮了
指令还有很多,你们输入 @ 就会有提示了,比如 deprecated ,标记已弃用
这时你使用它就会有个提示,并且划上一根线
-
MarkDown 文档注释
有时候,指令可能不够用,这时就可以使用 MarkDown 语法了
-
结合 TS
定义类型时,写上文档注释,当你鼠标悬浮时,就能查看对应注释
函数重载情况下,文档注释要写在类型上才行,下面这种无效
要写在类型定义的地方才行
-
总结
如果你用的是变量、函数或是 TS 定义类型,你要写注释,那就一定要写 文档注释,我跪下来求求你了 😭
代码七宗罪
让我来细数一下这坨代码的罪行,然后引出另一个主题,美化代码
下面这段,这简直是"甲级战犯",
- 一堆变量写了或者导入了不用,放那恶心谁呢
- 注释了的代码不删 (虽然可能有用,但是真丑)
- 都什么年代了,还在用
var
(坏处下面说) - 用行内注释和没写区别不大,要写就写文档注释 (文档注释的优点上面解释了,不再赘述)
- 小学生流水账一般的代码,连个函数入口都没提供,想一句写一句
- 连个代码格式化都不会,多按几个回车,你的键盘不会烂掉;每个分段加个注释,你的速度慢不了多少
- 硬编码,所有类型用字符串直接区分,你万一要改怎么办?

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

这玩意要我一行一行看?我是真的被恶心坏了
写代码要突出一个重点,看个大概,然后才能快速排查,看第三方库源码也是如此
我的习惯是写一个主入口,你叫 main | init | start 什么的都行,我只希望你能写上
然后主入口按照逻辑,给每个函数命名,这样一眼就能看出来你在干什么
如下图所示,这是我的偏好

我喜欢利用函数全局提升,把初始化函数放在文件顶部。这样每次打开一个文件,就能立刻看到大概逻辑
所以我很少用匿名函数,像上面那种全部写一坨,还都是匿名函数,我真的很难看出来谁是函数,谁是变量
这就引出一个新问题,函数的二义性
函数二义性
众所周知, JS 的类就是函数,里面有自己的 this ,可以 new 一个函数

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

而且用 const 定义,所以也就没了函数提升,严格来说,匿名函数才是真函数
不过我觉得直接写匿名函数有点丑,而且写起来似乎繁琐一点,虽然我都是用代码片段生成的
如果用了匿名函数,那么我就没了函数提升了
所以我仅仅在以下情况使用匿名函数
- 作为回调函数
- 不需要 this
- 函数重载
函数重载我来说说吧,应该挺多人不知道。
比如下图,针对每一种情况,写一遍类型,这样就能更加清楚描述函数的所有参数情况

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

格式化
这里可能有争议性,仅仅是我个人喜欢,看着舒服
大多数写前端的,基本人手一个 Prettier 插件自动格式化,再来个 EsLint
然后也懒得看配置,默认就是 2 格缩进,回车多了会被删掉什么的
这样下来,整个文件就相当臃肿,密密麻麻的,我看着很难受
我的风格如下
- 用 4 格缩进
- 代码按照语义类型分块,写上块级文档注释
- import 语句下面空两行,这样更加直观
- 每一段,用独特醒目的文档注释划分
- 定义变量优先使用 const ,并且只写一个 const
- 函数参数过长,则一行放一个参数
- 写行内样式以及较长字符串时( 比如函数作为字符串 ),用特殊的宽松格式书写,保持类似代码的格式化
- if 分支语句,要多空一行,看着清爽
下面来用图演示一下,不然看着上面的描述抽象
代码按照语义类型分块,写上块级文档注释
每一段逻辑写完,用个醒目的、大块的文档注释分开。
全部执行的逻辑,放在一个 init 函数中

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

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

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

var 的坏处
-
var 会变量提升,你可能拿到 undefined
-
var 没有块级作用域,会导致变量共享
按照常识,下面代码应该输出 0,1,2,3,4

但是你里面是异步打印,于是等你打印时,i 以及加了5次了,又没有块级作用域,所以你拿到的是同一个东西
在古时候,是用立即执行函数解决的,如下图。因为函数会把变量存起来传给内部

现在用 let 就行了

所以我求求你别用 var 了
最后,多用换行,我跪下来求求你了 😭