代码可读性
格式和测试
格式
读代码就像是读文章、小说、新闻
阅读的顺序一般来说都是从上到下,从左到右
- 竖向格式 {:&.rollIn}
- 横向格式
竖向格式
距离产生美
有距离的代码是这样的
…
const { UDFs, type } = this.props
const textFields = this.handleGroupByType('Text')
const numericFields = this.handleGroupByType('Numeric')
const timeFields = this.handleGroupByType('Time')
const datetimeFields = concat(this.handleGroupByType('Datetime'), timeFields)
const UDFsFunctions = sortBy(filterByUdfTypes(UDFs, [FUNCTION_TYPE_UDF]), UDF => UDF.name)
const UDAFsFunctions = filterByUdfTypes(UDFs, [FUNCTION_TYPE_UDAF])
const NORMALsFunctions = filterByUdfTypes(UDFs, [FUNCTION_TYPE_NORMAL])
const basicFunctions = isNotMetric(type) ? [...UDFsFunctions, ...NORMALsFunctions] : UDFsFunctions
const numericFunctions = filterByReturnType(basicFunctions, 'Numeric')
const textFunctions = filterByReturnType(basicFunctions, 'Text')
const datetimeFunctions = filterByReturnType(basicFunctions, 'Datetime')
const distinctUDAFs = uniqBy(UDAFsFunctions, 'name')
const aggregateFunctions = sortBy(distinctUDAFs, 'name')
const aggregateFunctionsFilter = filter(aggregateFunctions, aggregateFunction => aggregateFunction.tag != 'None')
return (
…
没有距离就变成下面这样了
…
const { UDFs, type } = this.props
const textFields = this.handleGroupByType('Text')
const numericFields = this.handleGroupByType('Numeric')
const timeFields = this.handleGroupByType('Time')
const datetimeFields = concat(this.handleGroupByType('Datetime'), timeFields)
const UDFsFunctions = sortBy(filterByUdfTypes(UDFs, [FUNCTION_TYPE_UDF]), UDF => UDF.name)
const UDAFsFunctions = filterByUdfTypes(UDFs, [FUNCTION_TYPE_UDAF])
const NORMALsFunctions = filterByUdfTypes(UDFs, [FUNCTION_TYPE_NORMAL])
const basicFunctions = isNotMetric(type) ? [...UDFsFunctions, ...NORMALsFunctions] : UDFsFunctions
const numericFunctions = filterByReturnType(basicFunctions, 'Numeric')
const textFunctions = filterByReturnType(basicFunctions, 'Text')
const datetimeFunctions = filterByReturnType(basicFunctions, 'Datetime')
const distinctUDAFs = uniqBy(UDAFsFunctions, 'name')
const aggregateFunctions = sortBy(distinctUDAFs, 'name')
const aggregateFunctionsFilter = filter(aggregateFunctions, aggregateFunction => aggregateFunction.tag != 'None')
return (
…
我也经常这样子做代码格式的处理
import React from 'react'
import Radio from 'antd/lib/radio'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import Button from 'components/commons/Button'
import VirtualFieldDropDownMenu from './VirtualFieldDropDownMenu'
import VirtualFieldPreview from './VirtualFieldPreview'
import VirtualMetricPreview from './VirtualMetricPreview'
import Notification from 'components/Notification'
import Title from './Title'
import { insertField, insertFunction, filterByReturnType, filterByUdfTypes } from './virtualFieldService'
import isNotUndefined from 'utils/lodash/isNotUndefined'
import * as ReportActions from 'actions/report'
import * as DataSetFieldsActions from 'actions/dataSetFields'
import * as ReportSelectors from 'selectors/report'
import isUndefined from 'lodash/isUndefined'
import trim from 'lodash/trim'
import isEmpty from 'lodash/isEmpty'
import concat from 'lodash/concat'
import uniqBy from 'lodash/uniqBy'
import sortBy from 'lodash/orderBy'
import filter from 'lodash/filter'
import { FUNCTION_TYPE_UDF, FUNCTION_TYPE_NORMAL, FUNCTION_TYPE_UDAF } from 'constants/BindingItemsConstants'
import './VirtualField.styl'
适当的距离
没有间距
handleAddNewUsers() {
const { newUsers } = this.state
if (isEmpty(newUsers)) return Notification.error('所选用户不能为空')
this.props.updateUsersInUserGroup(this.props.viewUserGroup.id, {userIds: newUsers}).then((response) => {
responseNotification(response, '添加成功')
this.setState({newUsers: []})
})
}
很多间距
handleAddNewUsers() {
const { newUsers } = this.state
if (isEmpty(newUsers)) return Notification.error('所选用户不能为空')
this.props.updateUsersInUserGroup(this.props.viewUserGroup.id, {userIds: newUsers}).then((response) => {
responseNotification(response, '添加成功')
this.setState({newUsers: []})
})
}
适当的间距
handleAddNewUsers() {
const { newUsers } = this.state
if (isEmpty(newUsers)) return Notification.error('所选用户不能为空')
this.props.updateUsersInUserGroup(this.props.viewUserGroup.id, {userIds: newUsers})
.then((response) => {
responseNotification(response, '添加成功')
this.setState({newUsers: []})
})
}
大家一起看看这段代码
handleSaveReport({ name, directory, isSaveAsCopy }) {
const { workingReport, reportId } = this.props
if (isSaveAsCopy) {
const requestParams = saveReportCopyRequestParams(name, directory, workingReport)
this.props.createReportCopy(requestParams, this.state.directoryOfCurrentReport).then(() => {
Notification.success('另存成功')
this.setState({openSaveReportDialog: false, isSaveAsCopy: false})
}).catch((errors) => forEach(errors, error => Notification.error(error)))
} else {
const request = saveReportRequestParams(name, directory, workingReport)
this.props.saveWorkingReport(reportId, request, this.props.currentPageId).then(() => {
Notification.success('报表已保存')
this.setState({openSaveReportDialog: false, isSaveAsCopy: false})
}).catch((errors) => forEach(errors, error => Notification.error(error)))
}
}
修改意见
handleSaveReport({ name, directory, isSaveAsCopy }) {
const { workingReport, reportId } = this.props
if (isSaveAsCopy) {
const requestParams = saveReportCopyRequestParams(name, directory, workingReport)
this.props.createReportCopy(requestParams, this.state.directoryOfCurrentReport)
.then(() => {
Notification.success('另存成功')
this.setState({openSaveReportDialog: false, isSaveAsCopy: false})
})
.catch((errors) => forEach(errors, error => Notification.error(error)))
} else {
const request = saveReportRequestParams(name, directory, workingReport)
this.props.saveWorkingReport(reportId, request, this.props.currentPageId)
.then(() => {
Notification.success('报表已保存')
this.setState({openSaveReportDialog: false, isSaveAsCopy: false})
})
.catch((errors) => forEach(errors, error => Notification.error(error)))
}
}
划重点(此处用力敲黑板)
1.有关联的代码放在一块,并且与其他代码块用空行隔开(垂直方向上的靠近与距离)
2.垂直顺序(自上而下的展示函数调用依赖顺序)
横向格式
横向的间隔与靠近
有横向间隔的代码
const quarter = Math.floor((today.getMonth() + 3) / 3)
删除这些横向间隔
const quarter=Math.floor((today.getMonth()+3)/3)
强调运算优先级
…
const XXX = (Math.…) + (a*2)
…
横向格式应有空格的地方(此处用力敲黑板)
- 运算符前后:
const view = this.props.view
- 函数花括号前:
handleChange() { … }
- 逗号后面:
handleSave(arg1, arg2) { … }
['a', 'b', 'c']
- 解构:
const { id, name } = view
- ……
[slide]
{:&.rollIn}
格式(完)
测试
使用函数
describe('buildSelectorValue', () => {
it('should return new selector when oldSelectors is empty', () => {
const oldSelectors = {}
const originalSelector = buildOriginalSelector(1, ['四川'])
const exceptSelector = buildExceptSelector(1, ['四川'])
expect(buildSelectorValue(oldSelectors, originalSelector)).to.eql(exceptSelector)
})
})
使用常量
it('should return selectors deleted by viewId', () => {
expect(deleteSelectorByViewId(twoViewsState, deleteSelectorViewId)).to.eql(oneViewState)
})
const deleteSelectorViewId = '1'
const twoViewsState = {
'1': {
pageId: 1,
dataSetId: 3,
values: [{
fieldId: 4,
selectorValues: ['四川']
}]
},
'2': {
pageId: 1,
dataSetId: 3,
values: [{
fieldId: 4,
selectorValues: ['广东']
}]
}
}
…
使用函数和常量的利与弊
| 利 | 弊
:-------|:------:|--------
函数 | 便于重用 | 逻辑复杂
函数 | 不会暴露细节 | 不够直观
常量 | 无逻辑 | 重复太多
常量 | 够直观 | 异常点不是很明确
网友评论