[持续收集]前端协作开发的一些配合

440 阅读7分钟

前言:工作和生活中"团队"、"团队作业"、"杀戮小队"、"复仇者联盟"这些词并不陌生,这些词的来由是因为其行事风格辨识度极高,或团队之间沟通效率高、成本低。整个团队的运作效率极高。因此而冠以"团队"这样字眼。而其不可或缺的当然就是之中的队员配合与默契和一些大家都遵循的行为标准。作为从“暑期夏令营学了3个月的超文本标记语言”的前端开发人猿来说,我觉得需要先从自身定制一套代码行为规范,起码让自己先了解自己的代码风格规范并遵循,自然而然的再来谈团队之间的默契。以下是我目前觉得可行的一些代码规范

《命名》:

1、const 命名常量:
  • "常量"一词通俗来讲是不变化的量,但是在开发当中,我更愿意理解为在该块级作用域中不会改变的量,因此在函数之中一些约定不变的量都应该被命名
  • 而常量命名的规则遵循 大写字母+下划线+大写字母+下划线... 的形式应该让人容易接受 XXXX_XXXX 同时大写字母在代码片段中也比较醒目,在查看块级作用域时常量清晰可见
    // good
    const FOOD_NUM = 3;
    const TOTAL_PEOPLE = 4; 
    let eat = FOOD_NUM / TOTAL_PEOPLE; 
    
    // bad
    let eat = 3 / 4;
2、let 命名变量:
  • 在该作用域中会变化的量,开发当中会变量的量应该有很多,用途甚多,大写字母过多则让人眼力疲惫,因此我更忠于小驼峰命名法
  • 普通变量遵循 命名+数据结构 这样的规则:xxxList、xxxObj、xxxString、xxxNumber...
  • boolean类型的变量:isXXX、hasXXX、canXXX...
  // bad
  let a = [] // 语义不明确
  let dc = [] // 不通用的缩写,不知道是什么
  let sb = '' // 容易产生冲突,实则为水杯英文简写
  let bookData = [] // 书本数据,但是不知道什么类型
  let sex = ... // 性别变量类型不明确, 例如1、"0为男 1为女 3为未知" 2、"'男'就是男 '女'就是女"
  
  // good
  let isBook = true // 清晰明了,这是是否为书的boolean类型
  let bookList = [] // 清晰明了,这是一个书本的Array集合
  let studentObj = {} // 清晰明了,这是一个学生的Object对象
  let ageNum = 18 // 清晰明了,这个年龄变量为数字类型
  let sexStr = '男'// 清晰明了,这个性别变量为字符串
3、属性命名:
  • 避免冗余
  // bad
  let studentObj={
    studyName: "马冬梅" 
  }

  /*
  * studyName中study就是冗余的,name属于studentObj对象。所以不必写成studyName。
  *
  */
  
  // good
  let studentObj={
    name: "马冬梅"
  }
4、函数命名:
  • 小驼峰命名法: 行为+XXX+数据类型
  // 很明显能看出:这个函数的作用是获取学生列表数组
  function getStudentList(){
    ...
  }
  
  // 很明显能看出:这个函数的作用是查询学生是否录取 且结果为boolean值
  function queryStudentIsPass(){
    ...
  }

  // 很明显能看出:这个函数的作用是跳转页面
  function jumpPage(){
    ...
  }
5、循环项命名
  • 根据当前循环列表的对象命名:
  // bad
  studentList.forEach((item)=>{
    ...
    // something
    ...
    let list = item.books.map((e=>{
      ...
      // something
      ...
    }))
    ...
    // something
    ...
  })

  /*
  * item和e和studentList看起来毫无关系,当forEach内的逻辑复杂需要修改的时候,
  * 在循环遍历时,很多人会使用item,value,e等代表遍历的当前项。
  * 当forEach内的逻辑复杂导致上下文过长时,这样的命名可读性就会变得非常差。
  * 你可能还需要翻到上面去看item和e表示什么,我们需要一个清晰的变量命名。
  * 这样维护代码的时候我们可以迅速理解这个变量代表的含义,而不是维护代码的时候必须去翻看复杂逻辑的上下文。
  */

    // good
    studentList.forEach((student)=>{
    ...
    // something
    ...
    let list = student.bookList.map((book=>{
    ...
    // something
    ...
    }))
    ...
    // something
    ...
  })

《函数》:

1、形参设置默认值
  • 当函数存在传参的时候:
  // bad  代码冗余,增加阅读量
  function getStudentList(currentPage, pageSize) {
    currentPage = currentPage || 1
    pageSize = pageSize || 10
    ...
    // something
    ...
  }

  // good   赋默认值,一个字:绝!
  function getStudentList(currentPage = 1, pageSize = 10) {
    ...
    // something
    ...
  }
2、形参个数限制:
  • 如果形参超过3个,可以直接将形参合并为一个对象,这样调用该函数时也能清楚的理解每一个形参的含义。如:
  // bad  形参过多,代码冗余,增加阅读量
  function getStudentList(currentPage = 1, pageSize = 10, search = "", startTime = "", endTime = "") {
    currentPage = currentPage || 1
    pageSize = pageSize || 10
    ...
    // something
    ...
  }

  // good  合并形参,无需记住顺序,一个字:绝!
  let searchData = {
    currentPage: 1, 
    pageSize: 10, 
    search: "", 
    startTime: "", 
    endTime: ""
  }
  function getStudentList(searchData) {
    ...
    // something
    ...
  }
3、参数结构赋值
  • 函数参数越少越好, 如果参数较多, 可采用解构, 不用考虑参数的顺序
   // good
   function createMenu({ title, body, buttonText, cancellable }) {...}
   createMenu({
     title: "Foo",
     body: "Bar",
     buttonText: "Baz",
     cancellable: true
   });
   
   // bad
   function createMenu(title, body, buttonText, cancellable) {...}
4、函数的功能限制
  • 一个函数应该只对应一个功能,按功能来创建函数才是正确的做法,这不仅易于理解和维护,同时也能让别人阅读你代码的时候心情舒畅
  // bad
  function init() {
    axios.get('/studentList').then((success)=>{
      ...
      // something
      ...
    })
      ...
      // something
      ...
    axios.get('/bookList').then((success)=>{
      ...
      // something
      ...
    })
  }

  // good
  function getStudentList() {
    axios.get('/studentList').then((success)=>{
      ...
      // something
      ...
    })
  }
  function getBookList() {
    axios.get('/bookList').then((success)=>{
      ...
      // something
      ...
    })
  }
  function init(){
    getStudentList()
    getBookList()
  }

《备注》:

1、不必注释的情况
  • 命名语义化的代码不必注释。如果你的命名很标准,不需要注释别人也能看懂
  let studentList = ["小日","小月","小明"] // 一眼就知道这是一个学生的列表数组,还需要什么注释呢?
  function getStudentList(){} // 一眼就能看出这是获取学生列表数组,还需要什么注释呢?
2、单行注释
  • Js中使用 // 单行注释,一般在注释对象后面直接写,或者在注释对象上面单独一行使用。如果单独一行,最好在注释前插入空行,使得注释与上面一行保持距离,能看出注释针对的是下面代码
  // bad
  let sb = "j100" // 这是啥???
  function getUCData(){}  // 这是啥???

  // good
  let sb = "j100" // sb是水杯的意思,又忘了水杯的英文,暂时用sb代替

  // 这个函数用于获取UC的某些数据,不需要管它
  function getUCData(){} 
3、多行注释
  • 使用 /** ... / 作为多行注释。包含描述、指定所有参数和返回值的类型和值。 / *@关键字 说明 */ 多用于注释函数例子:
  // bad  无注释,要完全看一遍才能理解当前函数作用
  function addTips(text="无内容", time=1500) {
    let oldTip = document.querySelector(".window-new-tips")
    oldTip? document.body.removeChild(oldTip) : ''
    let tip = document.createElement("p")
    tip.classList.add("window-new-tips")
    tip.innerText = text
      tip.style.cssText = "z-index: 9; position:fixed; top:40%; left:50%; transform: translate(-50%,-50%); opacity: 0.6; background: #000000; border-radius: 0.06rem; font-size: 14px; color: #FFFFFF; text-align: center; padding: 0.1rem 0.35rem;"
    document.body.appendChild(tip)
    setTimeout(() => {
        document.body.contains(tip)? document.body.removeChild(tip) : ''
    }, time)
  }

  // good  写了注释一目了然,不需要完全看懂函数内容即可知道作用
  /**
  * @param text:展示的文本, time:展示的时长
  * @return 无
  * @example formatNumber("没有更多了",1500);
  * @description 自定义提示信息,可自定义展示文本和展示时长
  */
  function addTips(text="无内容", time=1500) {
    let oldTip = document.querySelector(".window-new-tips")
    oldTip? document.body.removeChild(oldTip) : ''
    let tip = document.createElement("p")
    tip.classList.add("window-new-tips")
    tip.innerText = text
      tip.style.cssText = "z-index: 9; position:fixed; top:40%; left:50%; transform: translate(-50%,-50%); opacity: 0.6; background: #000000; border-radius: 0.06rem; font-size: 14px; color: #FFFFFF; text-align: center; padding: 0.1rem 0.35rem;"
    document.body.appendChild(tip)
    setTimeout(() => {
        document.body.contains(tip)? document.body.removeChild(tip) : ''
    }, time)
  }
4、变量赋值
  • 同名变量赋值 通常出现于对接口返回数据进行赋值, 接口返回字段较多时, 代码会显得冗余, 看起来很费劲! 因此, 开发当中接口返回字段于本地开发时声明的变量同名时, 我们可以这样来优化, 干净又卫生 ↓
// bad  代码冗余 不够美观
   this.form.a = res.a;
   this.form.b = res.b;
   this.form.c = res.c;
   this.form.d = res.d;
   this.form.e = res.e;
   ...

// good  代码简洁 省去不必要重复的代码片段  干净又卫生
    ['a','b','c','d','e',...].forEach(name =>{
       this.form[name] = res[name]
    )}