编码风格约定
编码风格约定
天风霁月 发表于2年前
编码风格约定
  • 发表于 2年前
  • 阅读 4965
  • 收藏 189
  • 点赞 14
  • 评论 25

腾讯云 十分钟定制你的第一个小程序>>>   

摘要: 基于angularjs项目的编码风格约定总结。真正写这个的原因是因为项目中乱七八糟的代码实在是太让人无语了。甚至有人用a,b,c这种完全无意义的参数名,很多时候我对中国的程序员想的可能太理想了,尤其是在前端,一大堆从静态页面转过来的所谓的程序员,他们缺少必要的编程素养甚至连技术追求都没有,换句话说就是欠调教。

[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表单验证

  1. 引用angular-messages实现验证信息的展示
  2. 表单提交使用ng-submit
  3. 禁止浏览器的验证 novalidate
  4. 使用form.waiting来避免表单重复提交
  5. 使用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多行代码究竟谁先谁后的约定。顺序依次是:

  1. scope变量定义在最前;
  2. scope底下的function;
  3. controller内部函数;
  4. 初始化函数定义及调用

注:只要是在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();
    }
  }
})
共有 人打赏支持
粉丝 6
博文 6
码字总数 8841
评论 (25)
0x0bject
未完待续的样子……保持关注……
dimdim
然而
短一点
并卵
走起来
Good!
Raynor1
嗯。看着还是可以的。赞一个。。
lxbzmy

引用来自“原来我还注册过这个号”的评论

并卵
+1 写满满屏幕的英文只比拼音缩写好一些。 没有一行中文注释仍然需要比做阅读理解要难。
甩葱哥
强行有道理的观点,不要误人子弟
黑传说
驼峰写法(组合键)不如 连字杆(一键)快啊。
51pansou
代码看着很舒服 ,32个赞
cyper
我对代码风格/命名也有强迫症.
巴顿
禁止使用中文拼音以及拼音缩写.....
日常检查规范条例,这个变量,你帮我命名一下。
Arrowing
粗粗一扫,
试图模型定义的约定 -> 视图模型定义的约定
御风林海
对于中国的老板只要结果,不注重过程。不断压缩时间。严重加班,程序员只能赶工的现象,你怎么看
l00ps

引用来自“Raynor1”的评论

嗯。看着还是可以的。赞一个。。

+1
OpenIoT
是ISO,还是iOS,确认下?
护士的小黄瓜

引用来自“巴顿”的评论

禁止使用中文拼音以及拼音缩写.....
日常检查规范条例,这个变量,你帮我命名一下。

还有红包 支付宝 余额宝 搜狗 百度等都用英语给我翻译一下
for7020
代码看着很舒服,请教一下楼主,factory缓存了数据,而切换了用户需要清除factory的缓存要怎么实现呢?
天风霁月

引用来自“for7020”的评论

代码看着很舒服,请教一下楼主,factory缓存了数据,而切换了用户需要清除factory的缓存要怎么实现呢?
用户的基本信息(例如id,username等常用信息)会保存在cookies里面及$cookies中,而用户的详细信息保存在userService下面,对出登录清除cookies,另,登录登出也可以抽象出loginLogoutService,或者sessionService
for7020

引用来自“for7020”的评论

代码看着很舒服,请教一下楼主,factory缓存了数据,而切换了用户需要清除factory的缓存要怎么实现呢?

引用来自“天风霁月”的评论

用户的基本信息(例如id,username等常用信息)会保存在cookies里面及$cookies中,而用户的详细信息保存在userService下面,对出登录清除cookies,另,登录登出也可以抽象出loginLogoutService,或者sessionService
感谢楼主的回答,现在是这样的,我把当前用户的订单记录数据缓存在orderService,联系人数据缓存contactService,等等子模块Service缓存了属于当前用户的数据,切换了用户不知道该怎么清除各个Service缓存的上一个用户的数据.楼主有处理过这样的情况吗?
天风霁月

引用来自“for7020”的评论

代码看着很舒服,请教一下楼主,factory缓存了数据,而切换了用户需要清除factory的缓存要怎么实现呢?

引用来自“天风霁月”的评论

用户的基本信息(例如id,username等常用信息)会保存在cookies里面及$cookies中,而用户的详细信息保存在userService下面,对出登录清除cookies,另,登录登出也可以抽象出loginLogoutService,或者sessionService

引用来自“for7020”的评论

感谢楼主的回答,现在是这样的,我把当前用户的订单记录数据缓存在orderService,联系人数据缓存contactService,等等子模块Service缓存了属于当前用户的数据,切换了用户不知道该怎么清除各个Service缓存的上一个用户的数据.楼主有处理过这样的情况吗?
没有遇到这样的情况,是否可以考虑在退出的时候清理相关service下的数据,或者单独写一个serviceManage用来管理所有的service,在每个service下面开放clean接口,然后将service加入到serviceManage中,然后处理
×
天风霁月
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: