编码风格约定
转自:http://my.oschina.net/u/924762/blog/602270?fromerr=n9vfH2xH
摘要
[toc]
编码风格约定
写在最前面
-
一个统一的好的编码风格好过一打大牛 -
你怎么看别人的代码呢?
每个人都有自己的编码风格,这个受到个人的学习以及工作历程影响。
多人协同开发,不可避免的会遇到一个功能几个人一起开发,或者同一个功能,前后由不同的人开发。这个时候问题来了,如果是你,你会怎么看待别人的代码呢?呵呵,这其实已经不言而喻了。
- 那又怎么样?
说实话对于个人来说,真不能怎么样,谁没有一两个满是坑的项目呢,又有谁不是从最开始的垃圾代码中慢慢提炼出自己的编码风格呢。
但是对于一个项目,那太可怕的,不会有人会想要遇到这样的项目,很多人会在项目风险爆发之前溜之大吉,留下满地狼藉,等待重建。
但是你真的希望你自己的项目,亲手写的代码,最后会是这样的结果?或者当你进入一家新公司的时候,竟然拿不出一点可以用来的炫耀的东西。
- 我们要怎么做?
如果每一回看到别人的代码都痛不欲生,那么我们的人生还有什么快乐。你要相信你不会永远只关注于你自己的一个小角落。
那么我们要怎么做呢?如果你能看别人的代码如同你自己的写的,你写的代码每一行都是犹如ISO般的标准,那么是不是会有这样的感觉:“我靠,我当初怎么这么傻”。
这就是我们现在要做的,
统一编码风格:不同的人写一样风格的代码,对应业务处理有着相同的代码逻辑。
- 约定大于规范
讲了这么多,只是为了阐述
统一编码风格的重要。在这里我需要提出这样一个概念:约定大于规范,及凡是在约定范围里的内容,必须被不折不扣的实行,否则我们的这些约定又有什么意义呢。
- 期待以后更多的约定
现在定义的这些肯定不会是全部,在以后的开发中必然会遇到更多的问题,从而提炼出更多的约定,这是好事情,也是正确的方向。让我们满怀期待这样盼望。
编码风格基本约定
BB了半天,让我们进入正题,这篇文档既是这次代码重构的指导文档,也会是前端小组的内部代码规范定义文档,用来给每一个新加入的兄弟姐妹们套上一个足够结实的辔头,以约束你们过于奔放的想法,编程毕竟是一个严谨的工作。
缩进及空格的约定
- HTML缩进
DOM元素 缩进是两个空格,便于在屏幕中展示更多的内容。
ng指令换行且缩进4个空格
<div id="" name="" class=""
ng-show=""
ng-click-""
ng-class="">
</div>
- JS缩进
缩进是两个空格
- 变量赋值的空格
为了方便理解,用[ ]代表一个空格。
var i = 0; // var[ ]i[ ]=[ ]0;
var i, j; //var[ ]i,[ ]j;
var i = 1, j = 2; //var[ ]i[ ]=[ ]1,[ ]j[ ]=[ ]2;
-
function定义的空格
-
函数表达式函数定义
var不能省略
var somting = function (p1, p2, p3) {s
}
//var[ ]somting[ ]=[ ]funtion[ ](p1,[ ]p2,[ ]p3)[ ]{}
- for的空格
for (var i=0; i<list.length; i++) {
}
//for[ ](var[ ]i=0;[ ]i<list.length;[ ]i++)[ ]{}
for (key : obj) {
}
//for[ ](key[ ]:[ ]obj)[ ]{}
- if的空格
if () {
} else {
}
//if[ ](true)[ ]{}[ ]else[ ]{}
- object中的空格
var obj = {
doSmting: function () {
},
list: [{}, {}]
}
/*
var[ ]obj[ ]=[ ]{
doSomting:[ ]function[ ]()[ ]{
},
list:[ ][{},[ ]{}]
}
*/
- JSON中的空格
var obj = {1: "", 2: ""}
//var[ ]obj[ ]=[ ]{1:[ ]"",[ ]2:[ ]""}
引号的使用
- 单引号
js代码中统一使用单引号,设计一些html模板时单引号内部可以使用双引号
- 双引号
html代码中统一使用双引号
命名规范及约定
这项本来是不想说的,但是作为未来前端代码规范文档,这里还是需要提一下。
禁止一切无意义命名,禁止全局变量的定义,rootScope中的变量需要统一在app.js中定义。
- 变量命名
变量的命名,首先是这肯定是一个名词,
禁止使用中文拼音以及拼音缩写。遵循小驼峰命名,首字符小写。scope底下禁止独立变量的存在。禁止省略写法,var 必须写
var isBoolean = true; //布尔值以is开头
var arrayList = []; //数组以List结尾
$scope.type = 1; /**这种写法是禁止使用的**/
- 函数命名
函数一般是执行一组操作的代码块,所以用动名词结合的方式命名,使用var name = function(agrs)。函数内部需要用到一些关键参数,作为入参传入,即使在scope中存在,也需要作为入参传入(好处是提高函数复用的可能)。
当前项目中不需要匿名函数(回调函数除外),以及自运行函数。
var getSomting = function (id) {} //获取某个值
var loadSomting = function (agrs[]) {} //从后台加载数据,涉及到restService
var postSomting = function (obj{}) {} //提交表单操作,新建
var deleteSomting = function (id) {} //删除操作
var putSomting = function (id, obj{}) {} //提交表单操作,修改
var initSomting = function () {} //初始化函数,一般是用来获取某个获取后台的某个资源
$scope.views = {
showSomting: function () {}
chooseSomting: function () {}
}
- controller的命名
controller的命名为首字母大写的大驼峰规则(PS:这个写法不知道是从哪里流行起来的,似乎大家都是这么用的)。
- factory的命名
factory的命名为首字母小写的小驼峰规则,英文命名,尽量精简同时语义明确。
- directive的命名
同factory
全局静态常量定义约定
这里的全局常量需要定义在单独的app_static.js文件下,方便统一管理以及协同开发。定义一个全局的常量约定如下:
命名:全大写英文,用下划线"_"分割单词
定义方法: constant() 或者 value()
angular.module('myApp.static', [])
.constant("USER_TYPE", {1: "个人", 2: "企业"})
全局动态变量定义约定
全局的动态变量来自后台提供的一些业务数据,大部分来自数据库字典表,这里使用factory的定义service的方式来实现全局动态变量的定义,约定如下:
命名:全大写英文,用下划线"_"分割单词
定义方法: factory
angular.module('myApp.somting',[])
.factory("SOME_TYPES", function ($resource) {
var SOME_TYPES = {};
$resource(url, 'GET').then(function (result) {
SOME_TYPES = result
});
return SOME_TYPES;
})
注释约定
注释是用来解释当前代码的功能,一个好的注释就是能让人一眼看懂复杂的内部实现逻辑,而一个规范的注释能够形成最后的api文档。当然最重要的是注释可以你知道究竟该找谁痛扁一顿,所以凡写过必留下痕迹。
- 文件注释
写在文件的最开头
/**
* @author
* @date
* @module name
* @description
*/
- controller注释
写在controller内部第一行
.controller(function () {
/**
* @author
* @date
* @controller name
* @description
*/
})
- 函数注释
写在函数外面,入参和出参如果没有就不要写
/**
* @fuction name
* @param {agr[0]:"描述",agr[1]:"描述"}
* @return {agr[0]:"描述",agr[1]:"描述"}
* @description
* @author
* @date
*/
function () {
return ;
}
- 行注释
单行注释
var obj = "" ; //参数定义注释
function () {
...
// 对函数内部代码或者逻辑的特殊说明
...
}
基础数据模型定义的约定
基础数据模型依赖于后台接口提供的数据,同时根据前台具体的业务场景或不变或转换格式保存在前台缓存对象下,同时也可以将变化过的数据更新到当前数据模型中。
service中的函数命名,尽量精简,避免ById 之类的命名。
保留五种方法:getList,getDetail,post,update,delete
app.factory("userService",function ($q, $resource) {
var service = {
getList : function () {
//来自后台数据
return $q(function(resolve, reject){
//success resolve()
//failed reject()
})
}
getDetail : function (id) {
//来自后台数据
return $q(function(resolve, reject){
//success resolve()
//failed reject()
})
},
post : function (user) {
//来自后台数据
return $q(function(resolve, reject){
//success resolve()
//failed reject()
})
},
update : function (id, user) {
//来自后台数据
return $q(function(resolve, reject){
//success resolve()
//failed reject()
})
},
delete : function (id) {
//来自后台数据
return $q(function(resolve, reject){
//success resolve()
//failed reject()
})
}
}
return service;
})
form表单验证
- 引用angular-messages实现验证信息的展示
- 表单提交使用ng-submit
- 禁止浏览器的验证 novalidate
- 使用form.waiting来避免表单重复提交
- 使用form.field.blur=true/false/udefined来处理获得失去焦点以及初始化的情况。
<form name="myForm" ng-submit="postSomting" novalidate>
<div>
<span>用户名:</span>
<input type="text" name="username" placeholder="请输入URL信息"
ng-model="some.username" required
ng-pattern="REG"/>
<div>
<div ng-messages="myForm.username.$error">
<div class="error" ng-message="required">用户名不能为空</div>
<div class="error" ng-message="pattern">请输入正确的用户名</div>
</div>
</div>
</div>
<input type="submit" ng-disable="myForm.$validate" value="提交">
</form>
分号(;)使用
代码块的分号不可被省略,因为考虑到以后的压缩,混淆。
if中的{}省略
大部分的if判断,else 分支都是有一定意义的,只有某一些时候是可以省略的。if 直接return 可以忽略。
if (true) return;
if (true) return somtion;
ng-src和ng-href 代替 src、href
当src和href中包含$scope中变量时,使用ng-src和ng-href避免错误的网络请求
注:正常的静态资源地址不需要这样处理。
项目开发代码规范
变量的定义
- view 对象的使用
每个controller中都要定义 view 对象,即使是空的。
.controller(function($scope){
$scope.view = {}
})
- controller 中的变量
controller 禁止定义全局变量,变量只存在于函数内部,或者 view 上
代码顺序的约定
代码顺序既是对于controller中的N多行代码究竟谁先谁后的约定。顺序依次是:
- scope变量定义在最前;
- scope底下的function;
- controller内部函数;
- 初始化函数定义及调用
注:
只要是在scope中用到的变量全部需要最先声明。
.controller(function () {
/*scope底下的对象最先声明*/
$scope.somting = {};
/*scope底下的function*/
$scope.doSomting = function () {}
/*controller局部函数*/
var doSomting = function () {}
/*controller的初始化函数定义*/
var run = function () {}
/*运行初始化函数*/
run();
})
视图模型定义的约定
controller中的离散变量将通过scope.views(作为试图模型对象)统一控制,甚至某些复杂页面视图模型,可以在views中用单独的对象处理。
实际上针对数据模型,也有一篇正在写的博客“angular项目中实现数据分层”
//页面视图控制数据模型
$scope.views = {
somting: "",
isSomting: true,
chooseSomting: function () {
this.sonting = "";
},
oneObj: {
oneType: "",
showOne: fucntion () {
this.one = "";
}
}
}
//后台返回数据模型
$scope.somting = somtingService.get();
业务数据模型定义的约定
业务数据模型一般是有别于基础数据模型和视图数据模型,一般是包含视图内容的数据对象,例如表单数据对象,或者被选中的某些数据,这些数据一般用于界面控制也会提取出接口参数用于交互。
$scope.somtingSelectedList = [{
id: 1,
...
selected: true
}, {
id: 2,
...
selected: true
}, {
id: 3,
...
selected: false
}...]
一些数据模型会有一些相应的操作,这个时候可以使用数据对象来处理, 就函数以及数据本身包含在一个数据对象上。(
PS:尽量减少controller下面的孤立函数)
$scope.somting = {
list: [{}],
select: function(){},
delete: function(){},
getDate: function(){}
}
controller 中的初始化函数
大部分时候页面初始化需要controller的一些赋值操作,以及数据请求。这部分初始操作定义成 run 函数。
注:run是controller下的保留函数,不管有没有用到,都要定义,而且一定不要绑定在 $scope 下
.controller(function(){
var run = function(){
}
run();
})
ui-router的使用
计划开一篇“ui-router使用心得”
- 参数传递
使用$stateParams传递数据
//config中定义参数
$stateProvider.state('stateTo',{
url: '',
templateUrl: '',
params: {p1: '', p2: ''}
})
//state.go
$state.go('stateTo', {p1: '1', p2: '2'})
//controller中接收
controller(function($stateParams){
$stateParams.p1;
$stateParams.p2;
})
- resolve的使用
主要用来对controller依赖的service中的数据进行初次加载,同时避免由于数据单例造成的数据不同步问题。
最近的一些使用,发现resolve的使用有一些局限性,以及对代码结构的一些限制,也在考虑是否引入resolve的概念。其实在contrlller上面的一些处理也能实现数据加载展示的效果。保留意见。
$stateProvider.state('stateTo', {
url: '',
templateUrl: '',
resolve: {
someService:"someService",
init: function () { //方法名自定义,所有方法都会在页面加载前被调用
someService.load();
}
}
})

浙公网安备 33010602011771号