前言:
程序员都认同代码规范的重要性,本手册用实际例子来说明如何规范代码,提高可读性和维护性。
变量命名
变量命名不能太简单也不能太复杂,不要用难以读懂的简写方式
// ❌错误的示范:
let ord = 1; // 过于简单
let myGoodsOrderList = 1; // 过于复杂,有些单词是多余的
// ✅正确的示范:
let orderId = 1;
用知名其意的方式为变量命名,通过这种方式,当再次看到变量名时,就能大概理解其中的用意
// ❌错误的示范:
let daysSLV = 10;
let y = new Date().getFullYear();
let ok = true;
if(age > 30){
ok = true
}
// ✅正确的示范:
const MAX_AGE = 30;
let daysSinceLastVisit = 10;
let currentYear = new Date().getFullYear();
const isUserTooOld = age > MAX_AGE;
不要在变量名中添加额外的不需要的单词
// ❌错误的示范:
let nameValue;
let theProduct;
// ✅正确的示范:
let name;
let product;
不要简写变量上下文
// ❌错误的示范:
users.forEach(u => {
//...
//...
//...
register(u); // 当上面的代码很多时,这”u“是什么鬼?
//...
}
// ✅正确的示范:
users.forEach(user => {
//...
//...
//...
register(user);
//...
}
不要添加不必要的上下文
// ❌错误的示范:
const users = {
userName: 'John',
userSurname: 'ka',
userAge: 30
}
// ✅正确的示范:
const users = {
name: 'John',
surname: 'ka',
age: 30
}
去掉对阅读者没有意义的注释
// ❌错误的示范:
function getUserList() {
// 获取用户列表
ajax.post('userList').then(resp => {
}
}
// ✅正确的示范:
function getUserList() {
ajax.post('userList').then(resp => {
}
}
函数命名
使用长而具有描述性的名称,考虑到函数表示某种行为,函数名称应该是动词或短语,用以说明其背后的意图以及参数的意图。函数的名字应该说明他们做了什么。
// ❌错误的示范:
function notif(user) {
}
// ✅正确的示范:
function notifyUser(email) {
}
避免使用大量参数,理想情况下,函数应该指定两个或更少的参数。参数越少,测试函数就越容易,参数多的情况可以使用对象。
// ❌错误的示范:
function getUsers(fields, fromDate, toDate) {
}
// ✅正确的示范:
function getUsers({fields, fromDate, toDate}) {
}
使用默认参数替代 || 操作
// ❌错误的示范:
function getUsers(fromDate) {
let date = fromDate || ''
}
// ✅正确的示范:
function getUsers(fromDate = '') {
}
一个函数应该只做一件事,不要在一个函数中执行多个操作
// ❌错误的示范:
function notifyUsers(users) {
users.forEach(user => {
const userRecord = database.lookup(user);
if (userRecord.isVerified()){
notify(user)
}
}
}
// ✅正确的示范:
function notifyUsers(users) {
users.filter(isUserVerified).forEach(notify);
}
function isUserVerified(user) {
const userRecord = database.lookup(user);
return userRecord.isVerified();
}
不要污染全局变量,如果需要扩展现有对象,请使用ES6类和继承,而不是在原生对象的原型链上创建函数
// ❌错误的示范:
Array.prototype.myFunc = function myFunc() {
}
// ✅正确的示范:
class SuperArray extends Array {
myFunc() {
}
}
避免使用反面条件
// ❌错误的示范:
isUserNotBlocked(user) {
}
// ✅正确的示范:
isUserBlocked(user) {
}
使用条件简写,仅对布尔值使用此方法,并且如果确信该值不会是undefined 或null的,则使用此方法
// ❌错误的示范:
if(isValid === true) {
}
if(isValid === false) {
}
// ✅正确的示范:
if(isValid) {
}
if(!isValid) {
}
### 对象简写 对象尽量简写,比如 {name:name} 应当简写为 {name}
```javascript // ❌错误的示范: const name = 'John'; getList({name:name});
// ✅正确的示范: const name = 'John'; getList({name});
<a name="1ZIO2"></a>
### 双目运算简写
(userData.userPhoto)?userData.userPhoto:userLogo<br />改为:userData.userPhoto || userLogo
```javascript
// ❌错误的示范:
let img = userData.userPhoto?userData.userPhoto:userLogo
// ✅正确的示范:
let img = userData.userPhoto || userLogo
代码要简洁而不简单,代码要让阅读者觉得舒服
/* 找到提供的句子中最长的单词,并计算它的长度。函数的返回值应该是一个数字
例如:findLongestWord("The quick brown fox jumped over the lazy dog");
*/
// ❌错误的示范:
function findLongestWord(str){
let arr = str.split(' ')
let flagNum = 0
arr.forEach((ele)=>{
if(ele.length > flagNum){
flagNum = ele.length
}
})
return flagNum
}
// ✅正确的示范:
function findLongestWord(str){
let arr = str.split(' ');
return Math.max(...arr.map(item => item.length));
}
用对象map代替过多的if else,让代码更易读,易维护
/* 找到提供的句子中最长的单词,并计算它的长度。函数的返回值应该是一个数字
例如:findLongestWord("The quick brown fox jumped over the lazy dog");
*/
// ❌错误的示范:
// 1 正常; 2 待审核; 4 禁用; -1 驳回审核; -10 删除
if (this.detail.status === 1) {
return '已认证'
} else if (this.detail.status === 2) {
return '待审核'
} else if (this.detail.status === 4) {
return '已禁用'
} else if (this.detail.status === -1) {
return '驳回审核'
} else {
return '--'
}
// ✅正确的示范:
statusMap = {
1: '已认证',
2: '待审核',
4: '已禁用',
'-1': '驳回审核'
}
return statusMap[this.detail.status] || '--'
函数也可以用map优化(请仔细理解其中用意)
// bad
function(flag){
if(flag==="left"){
move("right");
}else if(flag==="right"){
move("left");
}else if(flag==="top"){
move("bottom");
}else if(flag==="bottom"){
move("top");
}
}
// good
// 更改后,语义更清晰,使用更灵活
var move = flag => { console.log(flag) }
var command = {
left: function(){
move("left");
},
right: function(){
move("right");
},
top: function(){
move("top");
},
bottom: function(){
move("bottom");
},
};
function moveTo(flag){
command[flag]();
}
moveTo('left')
利用 || 优化代码
// bad
if (value === "") {
value = "similar";
}
// good
value = value || "similar";
巧用正则优化代码
//(bad) 格式化字符串 fontSize => font-size
function stringFormat(str) {
var strArr = str.split(''),
len = strArr.length,
i = 0;
for (; i < len; i++) {
if(/^[A-Z]$/.test(strArr[i])) {
strArr[i] = "-" + strArr[i].toLowerCase();
}
}
return strArr.join('');
}
//(good) 格式化字符串 fontSize => font-size
function stringFormat(str) {
return (str.replace(/([A-Z])/g, "-$1")).toLowerCase();
}
更少的嵌套,尽早 return
// bad
let getPayAmount = () => {
let result
if (_isDead) result = deadAmount()
else {
if (_isSeparated) result = separatedAmount()
else {
if (_isRetired) result = retiredAmount()
else result = normalPayAmount()
}
}
return result
}
// good
let payAmount = () => {
if (_isDead) return deadAmount()
if (_isSeparated) return separatedAmount()
if (_isRetired) return retiredAmount()
return normalPayAmount()
}
利用空行让代码更易读
<!-- ✅正确的示范:-->
<uni-popup ref="showshare" @change="change" type="bottom">
<view class="uni-share">
<text class="uni-share-title">分享到</text>
<view class="uni-share-content">
<button open-type="share" class="uni-share-content-box" style="background: #ffffff;" @tap="cancel">
<view class="uni-share-content-image">
<img src="../../../static/image/weixin.png" class="content-image" mode="widthFix"/>
</view>
<text class="uni-share-content-text">微信</text>
</button>
<button class="uni-share-content-box" @tap="saveImg" style="background: #ffffff;">
<view class="uni-share-content-image">
<img src="../../../static/image/save-img.png" class="content-image" mode="widthFix"/>
</view>
<text class="uni-share-content-text">保存图片</text>
</button>
</view>
<text class="uni-share-btn" @tap="cancel('share')">取消分享</text>
</view>
</uni-popup>
正确选择组件
在使用VUE的UI组件库时,要根据功能而不是外观选用组件。 例如下面的UI需求,看似是tab,但如果它的行为是radio,那应该选用checkbox组件。
代码块重复2次以上,建议封装,重复3次以上,必须封装
// good,封装微信自带的toast,这样可以统一修改持续时间,并且在使用的时候代码更简洁
function showToast(msg, icon = 'none') {
wx.showToast({
title: msg,
icon,
duration: 2000
});
}
### css优化:书写代码前, 考虑并提高样式重复使用率 对于常用的按钮,文本,圆角,阴影等效果,做mixin或者全局class ```javascript .app-container { padding: 20px; margin-top: 80px; }
.text-center { text-align: center }
.link-type, .link-type:focus { color: #2E6FFF; cursor: pointer;
&:hover { color: rgb(32, 160, 255); } }
@mixin clearfix { &:after { content: ""; display: table; clear: both; } }
@mixin bg-image(url) { background: url('../../assets/' + url + ".png?" + $version) no-repeat top left; -webkit-background-size: 100% 100%; background-size: 100% 100%; }
@mixin icon-image(url) { display: inline-block; vertical-align: top; margin-right: 10px; background: url('https://piggy-bank-image.hupofintech.com/piggy/pumanzhu-2/' + url + ".png?" + $version) no-repeat center left; -webkit-background-size: 100%; background-size: 100%; }
<a name="gwgmm"></a>
###
<a name="s0vEN"></a>
### 外观模式、工厂模式在vue中应用
```javascript
<template>
<div>
<form>
<login
v-for='item of comInp'
:name = 'item'
:key='item'
></login>
</form>
</div>
</template>
<script>
import login from './login';
const inputList = {
login: ['Username', 'Password', 'ImgCode'],
mobile: ['mobile', 'Password']
}
export default {
name: 'Form',
data() {
return {
type: 'login'
}
},
components: {
login
},
computed: {
comInp(){
console.log(inputList)
return inputList[this.type]
}
},
}
</script>
// login.vue
<template>
<component :is='comInput' />
</template>
<script>
import Username from './input/Username'
import Password from './input/Password'
import ImgCode from './input/ImgCode'
import Mobile from './input/mobile'
const inpMap = {
Username,
Password,
ImgCode,
Mobile
}
export default {
name: 'login',
data() {
return {
codeStatus: 'img'
}
},
components: inpMap,
props: ['name'],
computed: {
comInput(){
return inpMap[this.name]
}
},
}
</script>
状态模式在vue中应用
<template>
<div>
<div>
<div>步骤一<span>{{state > 1 && '完成' || '未完成'}}</span></div>
<div>步骤二<span>{{state > 2 && '完成' || '未完成'}}</span></div>
<div>步骤三<span>{{state > 3 && '完成' || '未完成'}}</span></div>
<div>步骤四<span>{{state > 4 && '完成' || '未完成'}}</span></div>
</div>
<button v-if="canGoBack" @click="goBack">返回上一步</button>
<component :is="stepName" @getChildData = 'changeState' />
</div>
</template>
<script>
import step1 from './step/step1'
import step2 from './step/step2'
import step3 from './step/step3'
import step4 from './step/step4'
export default {
name: 'stepHome',
data() {
return {
state: 1,
cache: []
}
},
computed: {
stepName(){
const stepList = {
1: step1,
2: step2,
3: step3,
4: step4,
}
return stepList[this.state]
},
canGoBack(){
return this.cache.length > 0
}
},
methods: {
changeState(state){
this.cache.push(state)
this.$set(this, 'state', state)
},
goBack(){
this.cache.pop()
this.state = this.cache[this.cache.length - 1]
}
},
}
</script>
图片压缩
所有的大图都应当经过压缩,推荐在线压缩工具:tinypng.com/
参考
阮一峰的ES6规范: es6.ruanyifeng.com/#docs/style
VUE的风格指南:cn.vuejs.org/v2/style-gu…