写点什么

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

  • 2022 年 7 月 18 日
  • 本文字数:5212 字

    阅读完需:约 17 分钟

前言

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


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



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


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


  • 命名看心情,有时拼音,有时字母,甚至有时 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 提交也是前端开发规范的一部分,今天列举的一些规范并不十分全面,只是大冰块细心整理的一部分。无谓对错,毕竟规范没有对错之分,只要团队大家都遵守就是有益的。


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

发布于: 刚刚阅读数: 3
用户头像

还未添加个人签名 2022.07.01 加入

还未添加个人简介

评论

发布
暂无评论
3大类15小类前端代码规范,让团队代码统一规范起来!_7月月更_南极一块修炼千年的大冰块_InfoQ写作社区