3大类15小类前端代码规范,让团队代码统一规范起来!

这是我参与更文挑战的第4天,活动详情查看: 更文挑战

前言

首先讲个真实的段子,我在之前公司亲身遇到过的。

阳光明媚的上午,大家都在安静的敲代码,突然某脾气暴躁的全栈大佬大J大喊一声:这屎一样的代码是谁写的?老子找了半天的bug全是因为这个!大家面面相觑,因为不知道他说的是前端代码还是后端代码,并且不确定是不是自己写过的,毕竟谁能保证自己从没写过屎一样的代码呢?这时项目经理说:看git提交记录啊,找出来请大家喝奶茶。大J说:正在找了。过了好久,大J也没说是谁的代码,项目经理就问:找到了吗?大J缓缓地说:找到了,一年前我自己写的。。。

image.png

代码不规范,回首两行泪啊!

我相信大家都遇到过各种各样神奇的代码:

  • 命名看心情,有时拼音,有时字母,甚至有时1234。
  • 明明1行代码能搞定的,由于基础差,写了20行,还觉得自己挺牛。
  • 一个函数里面处理n件事情,动辄几十行,严重的甚至上百行。
  • 从来不写注释,还埋怨别人从不写注释。(这个说的真的不是我自己)
  • ……

像上面这些问题林林总总千奇百怪,列到明天也列不完。

所以今天,大冰块来把这些问题细分成了3大类和15小类的前端代码规范,希望对大家的开发过程有一些帮助。

命名篇

在所有的规范中,命名可以说是重中之重,一个好的命名习惯让代码看起来结构清晰明朗,数据查找快捷方便,不好的命名习惯让人摸不着头脑,找不到南北,不小心就陷进命名者的混乱泥潭中无法自拔。

命名最最基本的要求是:

命名单词准确可描述,避免不易理解的缩写,不知意义的字符等,不要冗余,尽可能短。
命名单词准确可描述,避免不易理解的缩写,不知意义的字符等,不要冗余,尽可能短。
命名单词准确可描述,避免不易理解的缩写,不知意义的字符等,不要冗余,尽可能短。

变量、常量、属性、函数命名

  1. 变量命名: 统一规范:小驼峰式命名法: 单词之间没有连接符,首字母小写,后续单词首字母大写。
    同时要注意变量的类型,例如boolean类型的值可以用isXXX、hasXXX、canXXX等命名;Array类型的值可以用xxxList、xxxArray方式命名;Object类型的值可以用xxxObj方式命名。如:
  // bad
  let a = [] // 语义不明确
  let dc = [] // 不通用的缩写,不知道是什么
  let bookData = [] // 书本数据,但是不知道什么类型
  
  // good
  let isBook = true // 清晰明了,这是是否为书的boolean类型
  let bookList = [] // 清晰明了,这是一个书本的Array集合
  let studentObj = {} // 清晰明了,这是一个学生的Object对象
复制代码
  1. 常量命名: 统一规范:大写字母+下划线符+大写字母 。如:BASE_URL
  // bad
  const baseUrl = "http://localhost" // 在其他地方调用时和常量没有区别,看不出是否能更改
  
  // good
  const BASE_URL = "http://localhost" // 很明显的知道这是一个常量
复制代码
  1. 属性命名: 统一规范:小驼峰式命名法: 单词之间没有连接符,首字母小写,后续单词首字母大写。如:
  // bad
  let studentObj={
    studyName: "马冬梅" 
  }

  /*
  * studyName中study就是冗余的,name属于studentObj对象。所以不必写成studyName。
  *
  */
  
  // good
  let studentObj={
    name: "马冬梅"
  }
复制代码
  1. 函数命名: 统一规范:小驼峰式命名法:单词之间没有连接符,首字母小写,后续单词首字母大写。如:
  // 很明显能看出:这个函数的作用是获取学生列表
  function getStudentList(){
    ...
  }

  // 很明显能看出:这个函数的作用是跳转页面
  function jumpPage(){
    ...
  }
复制代码

循环内当前项命名(避免依赖上下文命名)

  1. 统一规范:根据当前循环列表的对象命名。
  // 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. 项目总文件夹:小写字母+连字符+小写字母 。如:
  vue-element-admin // 作为项目总文件夹,一眼就能知道是什么项目
复制代码
  1. views或pages内的文件夹:小写字母+连字符+小写字母 。如:
  error-page // 作为页面的文件夹,命名要准确清晰,一眼就能知道是什么页面
复制代码
  1. components内的文件夹:大驼峰命名法: 单词之间没有连接符,首字母都要大写。如:
  HeaderSearch // 作为存放组件的文件夹,大驼峰命名能让它与其它文件夹区分开来,更易理解
复制代码

css,scss,less文件命名

  1. 统一规范:小写字母+连字符+小写字母 。如:
  element-ui.scss // css文件同样要单词明了简介,通过名字能知道它的作用范围
  element-ui.less
  element-ui.css 
复制代码

js文件命名

  1. 统一规范:小写字母+连字符+小写字母 。如:
  drag-dialog.js // js文件同样要单词明了简洁,通过名字能知道它的大致作用
复制代码

vue文件命名

  1. src和components内的vue文件:大驼峰命名法: 单词之间没有连接符,首字母都要大写。如:
/**
*入口文件及组件文件,大驼峰命名能让它与其它文件夹区分开来,更易理解。
*同样组件类文件单词要明了,通过名字能知道它的大致作用
*/
  SwitchRoles.vue
复制代码
  1. 其他文件夹内的vue文件:小写字母+连字符+小写字母 。如:
  auth-redirect.vue // 命名要准确清晰,一眼就能知道组件含义
复制代码

img文件命名

  1. 若是icon图标要体现在名字中。
  2. 统一规范:小写字母+下划线符+小写字母 。如:
  icon_up_arrow.png // 一眼就能明白:icon图标,向上的箭头
  bg_header.png // 一眼就能明白:这是一张头部的背景图片
复制代码

json文件命名

  1. 统一规范:小写字母+下划线符+小写字母 。如:
  china_city.json // 一眼就能明白:中国城市的json文件
复制代码

其它文件命名

  1. 统一规范:小写字母+下划线符+小写字母 。如:deploy-docker.sh
  deploy-docker.sh // 单词简洁,语义明了
复制代码

函数篇

形参设置默认值

给形参设置默认值,不需要在函数内处理当前形参未传值的情况。避免了代码冗余,可读性更强。如:

  // bad  代码冗余,增加阅读量
  function getStudentList(currentPage, pageSize) {
    currentPage = currentPage || 1
    pageSize = pageSize || 10
    ...
    // something
    ...
  }

  // good   赋默认值,一个字:绝!
  function getStudentList(currentPage = 1, pageSize = 10) {
    ...
    // something
    ...
  }
复制代码

形参个数限制

如果一个函数有5个以上的形参,你会发现读起来很累。并且形参是有顺序的,这意味着调用函数的时候你需要把传入的参数和形参一一对应起来,否则会出现意想不到的错误。

所以我们最好把函数形参控制在3个之内,如果形参超过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
    ...
  }
复制代码

函数功能限制

想感受被动辄数十行甚至上百行的一个函数支配的恐惧吗?它就静静的躺在那里:来呀,来深入了解我啊~ 除非你能完完全全理一遍,不然你就不知道它的作用~

一个函数应该只对应一个功能,按功能来创建函数才是正确的做法,这不仅易于理解和维护,同时也能让别人阅读你代码的时候心情舒畅而不是想骂你。如

  // 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()
  }
复制代码

注释篇

我生平最讨厌两种人:不写注释的人和逼我写注释的人。不得不说,写注释是个好习惯,可是认真写注释的程序员越来越少见了。

那么关于注释,有什么需要注意的呢?

不必注释的情况

命名语义化的代码不必注释。如果你的命名很标准,不需要注释别人也能看懂。如:

  let studentList = ["小日","小月","小明"] // 一眼就知道这是一个学生的列表,还需要什么注释呢?
  function getStudentList(){} // 一眼就能看出这是获取学生列表的方法,还需要什么注释呢?
复制代码

单行注释

js中使用 // 单行注释,一般在注释对象后面直接写,或者在注释对象上面单独一行使用。如果单独一行,最好在注释前插入空行,使得注释与上面一行保持距离,能看出注释针对的是下面代码。

  // bad
  let sb = "j100" // 这是啥???
  function getUCData(){}  // 这是啥???

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

  // 这个函数用于获取UC的某些数据,不需要管它
  function getUCData(){} 
复制代码

多行注释

使用 /** … */ 作为多行注释。包含描述、指定所有参数和返回值的类型和值。
/* *@关键字 说明 */
如:

  // 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)
  }
复制代码

后记

前端开发规范注定是绕不开的坎,记得之前有同事总是喜欢格式化代码,凡是他更改过的文件,哪怕只有1行,整个文件也会被他格式化。回头再看git提交记录,好家伙,历史的commit全被覆盖了~ 当然,git提交也是前端开发规范的一部分,今天列举的一些规范并不十分全面,只是大冰块细心整理的一部分。无谓对错,毕竟规范没有对错之分,只要团队大家都遵守就是有益的。

本文旨在提供一条前端项目及代码优化的思路,从而减少代码维护时的时间和人力成本。如果对你有帮助,点个赞就好,如果有错误欢迎指出交流。感谢阅读~

PS: 今天是参加掘金更文挑战的第4天啦,没有存稿的我,今天的博客又费了半天时间,再次吐槽自己好慢啊。

虽然没多少人看,也还是给自己引引流吧~ 更文挑战的文章目录如下:

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享