前端编码规范
前言
学习了业界一些对于编码风格的理论,结合一些业界比较推荐的规范风格,反观自身的编码习惯,总结出这么一份自己比较喜欢的规范风格。
html
html标签中有很多属性,这些属性假如没有一定的排列规则,会现得很乱,不整洁。以vue tempalte的html为例,我推荐一下属性排列优先级:
- id,ref,class等属于标签的标识排前
- v-if,v-for等操作类的属性
- v-model和带绑定的属性
- 无绑定的属性
- 事件绑定
另外属性个数大于三个要换行显示1
2
3
4
5
6
7
8
9
10<Tag
ref="tag"
v-for="(item,index) in tabsInfo"
:title="item.title"
:link="item.router"
:active="item.active"
:key="index"
palcehold="请输入"
@click="handleClick"
><Tag>
css
业界比较推荐的一种规范是BEM(块级元素修饰符),它可以让你的css模块化,变得易维护。
- http://getbem.com/naming/
- https://github.com/getbem/getbem.com/blob/master/src/styles/pages/home.styl
js
命名
计算机科学只存在两个难题:缓存失效和命名。 –Phil KarIton
命名一直是计算机科学里的一大难题,在名变量时我只要做到准确、名副其实就可以了,记住一点就是要做到让人阅读代码就像是阅读一本书,用代码述说故事。
在命名是我比较喜欢参照一下几点原则:
- 命名变量使用小写字母加下划线,这样是为了跟函数的小驼峰命名做区分,好让我一样就知道这是变量,而且使用名词或名词短语
- 命名常量使用大写字母加下划线
- 命名函数使用小驼峰,使用动词或动词短语,表示动作
- 命名类使用就大驼峰
函数
函数的第一规则是短小,第二规则是还要更短小。 –《代码整洁之道》
写函数我一般遵循以下几点原则:
- 短小。假如函数过长,你就要做拆分,最好不要超过20行。
- if else语句不要嵌套太深,最多两层。
- 好的函数只做一件事情,也就是单一功能原则,并且能用函数名表达函数的主要功能。这里有个技巧,就是函数越短小,功能越集中,就越能取个准确的命名。
- 参数不要过多,最好三个之内,三个以上要有足够的理由。
- 减少副作用。
- 错误提前返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function observe(obj) {
if (obj && typeof obj === 'object') {
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key])
})
}
}
改为:
function observe(obj) {
if (!obj || typeof obj !== 'object') return
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key])
})
} - 自上而下排版函数。类似读报纸一样,细节总上在一个段落的下面。函数内的函数就类比细节,把内函数声明的位置放在外函数下面,依次排列。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16function A() {
B()
C()
}
// 以下都是A的细节
function B() {
D()
}
--// D属于B的细节,放在B下面
function D() {}
function C() {
E()
}
--// E属于C的细节,放在C下面
function E() {} - 公共API函数要写注释。以下摘自tj大神co库里的一段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19/**
* Wrap the given generator `fn` into a
* function that returns a promise.
* This is a separate function so that
* every `co()` call doesn't create a new,
* unnecessary closure.
*
* @param {GeneratorFunction} fn
* @return {Function}
* @api public
*/
co.wrap = function (fn) {
createPromise.__generatorFunction__ = fn;
return createPromise;
function createPromise() {
return co.call(this, fn.apply(this, arguments));
}
};
如何能写出好函数呢?首先要记住好代码是改出来,好函数也一样,所以先把函数的主体逻辑写好,再参照规则改造就好了。
注释
“别给糟糕的代码添加注释,重新写吧。” –《代码整洁之道》
《代码整洁之道》这本书不建议我们给表意不明的代码添加注释。总结的理由如下:
- 好代码可以从函数名就知道意思,假如函数名表达不了代码意图,就需要改造代码。
- 注释是人写的,会有不准确性,有误人子弟的可能。
- 写注释的原因可能是代码难读,一遇到难读的代码就写注释会导致跟多难读的代码。
但是所有的注释都不应该写吗?肯定不是。
注释也分类型,没必要写的类型有:
- 喃喃自语类的注释,表意不明的信息。
- 多余的说明。这种注释像是翻译一遍函数名。
- 误导性的注释,就是不准确的描述了函数的意图。
- 评论类的注释。对代码的评论可以使用github的评论工具,没必要写在代码里。
- 骂人的注释。。
有必要写注释的类型有:
- 法律信息和开源信息类,或者是一个库开头的说明信息。
1
2
3
4
5/*!
* Vue.js v2.6.10
* (c) 2014-2019 Evan You
* Released under the MIT License.
*/ - 说明在某种场景,某种情况的注释,这种注释就是为了说明因为某种特殊的原因才有以下代码。以上代码说明了场景当B站点更新api data时,会以storage的方式通知,这就监听storage代码出现的原因。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 当B网站的api data更新时会通过storage通知这里
// 监听storage,实时更新api data
window.addEventListener("storage", (event) => {
console.warn('event', event);
const { key, newValue } = event;
const api_storage_key = `api_list_${this.tpl_config.app_name}`;
if (key === api_storage_key) {
console.log("storage change,key ", key)
this.$store.commit("initApi", {
data: JSON.parse(newValue).content || []
})
if (this.select_node.label === "Form") {
const api_name = this.props_temp.model.api
if (!api_name) return
const api = this.apilist.find(api => api.name === api_name);
// 需要更新当前Form面板关联api的参数配置
this.createFormContentWithApiConf(api)
}
}
}) - 对意图的解析。比如函数内部的某一段为什么这么写,是什么原因造成这样写的决定。
1
2
3
4
5
6
7
8
9renameComponent(name) {
switch (name) {
// Switch不能作为组件名注册
case 'SwitchRadio':
name = 'Switch'
break
}
return name
}, - 对于特殊常量的说明。
1
const TYPE_FORM = 0; // 上搜下标类模板
- TODO注释
1
TODO: 太慢,待优化!
- 公共API的注释
- 注释掉代码,有必要写明注释掉的原因,好让人知道改删掉还是不改删掉。
1
2
3
4
5
6
7
8
9for (let key in defaultData) {
this.props_temp[prop].relatedData[key] = {
label: key,
prop: key,
// 暂时去掉默认值
// value: defaultData[key],
inputType: "Input"
};
}