宗旨
一个命名提供的信息量越多,就是越好的命名。
最容易的事
声明一个变量,是编程里最简单的事了。
在学习编程之初,先要会的就是声明一个变量。
int a = 1;
最困难的事
命名又是我们工作中最有难度的事。
随着我们技术能力的提高,做的项目也越来越大,业务越来越复杂。命名稍微不注意,就变成一堆无意义或者误导我们的字符串。
之所以说命名困难,我的想法是命名不单是想一个单词就ok。需要更多的理解业务,理解我们使用的技术,才能做到最贴切的命名。
信息量
回到我们的宗旨,来看看命名都会给我们提供哪些信息量。
例1
var username = '卡哇伊';
这段代码中有个变量username,它为我们提供了一个信息。
- 这是一个代表用户名的字段。
例2
var _username = '卡哇伊';
这段代码是有个变量_username,它为我们提供了两个信息。
- 这是一个代表用户名的字段。
- 这是一个私有变量。我们把下划线开头的变量,称为私有变量。只有类内部可以访问。
例子3
class User {
constructor() {
this._name = '卡哇伊';
}
getName() {
return this._name;
}
setName(val) {
this._name = val;
}
}
User命名的信息
- 这是一个类。
- 用户的类。
- 为内部的变量提供上下文,所以用户名可以只写成_name,代表User的_name。如果还需要一个用户年龄的字段,可以只写成_age。
getName的信息
- 这是一个方法,由动词+名词组成。我们用动词或者动词+名词命名一个方法。因为方法本身就代表某种动作,所以这样命名很贴切。并且和类的字段(名词)做了有效的区分。这样你在其他地方使用user.get***。你就知道这是调用了user的一个方法。user.hand就是使用了user的一个字段。
- 拿到用户名。
读到这里,我想你大概知道我要说的什么意思了。我们通过命名的格式,用开头有下划线代表私有变量,用首字母大写代表是一个类。区分不同类型的成员,达到让代码拥有更多信息量的目的。
那么,重点就是掌握一套这样的命名规则,并严格贯彻这套规则。
工作中的实践
这里拿React写一个页面作为例子 首先我要新建一个Pages文件夹,然后新建一个ProductListPage文件夹,在里面建立index.js文件,代码如下:
class ProductListPage extends Component {
constructor(props) {
this.state = {
productList:[],
categroyOptions:[],
}
}
componentDidMount() { ... }
async requestProductList() { ... }
async requestCategroyOptions() { ... }
renderProductList() {
const { productList } = this.state;
return productList.map(product => { ... });
}
renderHeader() { ... }
render() { ... }
}
Pages文件夹:
- 页面文件夹,为其下的文件提供上下文,我是一个放置页面文件的文件夹。
- 表明我在项目的的位置,项目中还可以定义其他类别的文件夹,components文件夹,reducers文件夹,共同形成项目结构。
ProductListPage:
- ProductListPage代表我要写一个产品列表相关的页面。
- Page尾缀与Pages文件夹呼应。在项目中有特殊地位的文件,加尾缀是很有用处的,比如你的代码中出现一个productListReducer变量,你就知道它来自Redcer这个特定模块。
componentDidMount:
- 这里着重说一下react的声明周期方法,我认为这个命名是比vue的略好一点的。==因为越是系统级别的命名,越是要详细一点==。因为系统级别的方法,用的场景多,重名的几率就大。比如vue的created生命周期方法,一个新手不知道这个方法,在写一个私有方法的时候,恰好也是创建某事物的含义,就用了creacted命名,就造成了重名。
- componentDidMount的component又与组件呼应。明确的告诉我们这是组件的mount。
- 引伸出一条规则是:越局部的变量可以越短小。它可以充分的利用上下文解释自己。
productList:
- 这个变量与页面名字同名,我喜欢用这种方式告诉自己,这个变量是这个页面的主角。另外List尾缀也有强调这是个重要数据的意思,配角的列表数据我都喜欢加s,比如categroyOptions。这样利用List和s区分主次关系。
- 在列表变量进行循环的时候,循环体中就可以用product
requestProductList:
- 请求产品列表。
- request是一个关键动词,我赋予了它特别的含义,就是需要稍微花点时间才能取到的值,与get动词对应。
renderProductList:
- 渲染产品列表
- render是一个关键动词,是react的拥有特殊含义的词,渲染页面。
嗯,每个命名都满满的信息量,我们就得到了易读又工整的代码。
规则的破坏
值得注意的是,命名是件需要自律和习惯的事。比如某一天增加了一个产品包装页,我写成了goodsPackingPage。这样‘产品’这个有特殊业务含义的字段在项目中有了两个命名,product和goods,这就造成了一定的混乱。
我见过这样一个单文件,有2000多行的代码,同样代表品类,结果有三个单词type,catagory,class。起初我以为是不同的意思,这就造成了阅读的困难。你的代码越复杂,命名不当造成的问题越严重。
所以我们在写代码时,建立的命名秩序,就不能破坏它。一旦破坏,原本可以传达的信息,便不再可信。比如新写的私有字段不以下划线开头。那么以后在函数中看到变量,就不能根据是否已下划线开头,判断它是否是私有变量了。
结束语
判断一个命名是否糟糕,就是看它有没有传达信息。更糟糕的是,它传达错误的信息。
好的命名就是能传达更多信息。依靠的是你建立的命名秩序。
如果你对整洁代码很有兴趣。推荐《代码整洁之道》这本书。里面有更多详细的关于命名的技巧知识。