如何让你的代码更优雅

前言

你有没有骂过“前任”的代码?你的代码有没有被吐槽过?没有注释,命名随意,没有封装,结构混乱,一个页面几千行。。。。

如何写出优雅的代码,让自己不被吐槽,让人羡慕,接下来咱就一起聊聊如何写出优雅的代码,如果大家有更好的写法和经验,欢迎在评论区留言,一起学习

什么样的代码是优雅的代码

咱先聊聊,什么样的代码是优雅的代码,在我看来,优雅的代码包括以下方面,首先就是代码的简洁,能够使用一行代码解决的,就不要写两行及以上,其次就是便于阅读,代码不仅仅是用来让机器(服务器,浏览器)来运行的,而是需要用人来编写,维护的,可能是自己,也可能是现在的同事,未来的同事,这个就是代码的可维护性,还有一个就是我们很关注的就是性能,就比如我们经常写的循环,在满足业务功能条件的时候,能少一次循环就少一次循环,还有就是不再使用的引用类型的数据,要及时手动的进行内存的释放,(虽然有垃圾回收机制),但是早一点释放内存是不是更好呢

注释

注释,写代码少不了注释,尤其是优雅的代码,更少不了注释;注释是给人看的,可能是自己,也可能是同事以及未来的同事看的,(这几句话说了好多遍了),那么我们为什么要写注释,以及该怎么样去写注释呢?,接下来咱就先来聊聊注释

如何使用注释?(在哪些地方需要添加注释)

  通用的规则是在代码不清晰时需要添加注释,个人觉得包含以下几个方面:

  1. 难于理解的代码添加注释(逻辑比较复杂,嵌套层级比较多,传递参数不明显等)

  2. 可能被误认为错误的代码(没有按照正常套路出牌的代码   3. 数据的状态(就拿订单状态来说,订单可能有多钟状态,此时在写这段的叶落逻辑的时候,就把不同的状态表示的含义写上去,以后的维护,或者是有新人接收这个项目的时候能够更快的上手)   4. 其他注释(文档注释,变量注释,函数注释)

1.文档注释:

简单描述当前js文件作用,是页面js逻辑处理,还是公共的方法等

如果是vue项目则是描述出当前vue文件的作用,

2.变量注释:

注明变量是用来做什么的,来进行语义化的命名,需要注释的则加上注释

1// difference 2let uName = 'Symbol卢'; // 虽然用了驼峰,但是简写严重。无法直观看出变量的含义 3// grace 4let userName = 'Symbol卢'; // 语义化命名,不能过于缩写

3.函数的注释

参数注释包括参数的数据类型,参数的命名语义化,返回参数注释包括了默认值,已经返回参数的数据类型

例如:

1/** 2 * @description: 数据类型的检测的第二种方式 3 * @param {any} data 要检测数据类型的变量 4 * @return {string} type 返回具体的类型名称【小写】 5 */ 6export const $typeOf = (data) => { 7 return Object.prototype.toString.call(data).replace(/\[object (\w+)\]/, '$1').toLowerCase() 8}

可以在vscode的插件市场,下载koroFileHeader 进行安装,可以一键生成注释格式

变量

定义变量的准则:变量用小写(声明变量用let),常量用大写(声明常量用const),变量命名语义化,指定变量的数据类型,避免使用太多的全局变量,先声明,后使用

1. let和const 取代 var

定义常量

1// difference 2var myLove = 'My love is Code';//没有使用const进行命名,且常量名称没有全部大写 3 4// grace 5const MY_LOVE = 'My love is Code';

使用 var 关键字 定义的 常量 是可以变化的,也就是,我们定义一个常量之后,还可以给它赋值来改变这个常量,然后按照我们在程序当中的规范,在声明一个常量之后,这个常量在整个程序也就全局中是不能够再被改变的,所以声明一个常量,要使用关键字 const 来声明常量,并且通常常量的名称都是大写的,并且语义化,让人看到这个常量的时候,就知道这个常量是干什么的

刚好聊到了常量声明中的字符串,那咱再看看,在使用字符串常量的时候,要注意哪些规范,上代码

1//要注意。静态字符串一律使用单引号或反引号(模板字符串),不使用双引号,动态字符串使用反引号,拒绝使用 + 进行字符串的拼接 2// difference 3const name = "Symbol卢"; 4const say = 'My name is' + name + 'and I love FE'; 5 6// grace 7const NAME = 'Symbol卢'; 8const b = `My name is ${ NAME } and I love FE`;

定义变量

定义局部的变量的时候使用let ,定义全局的变量的时候使用var,要记住一个原则就是,变量的声明要只在其声明的代码块中有效

1if (true) { 2 let x = 'hello'; 3} 4let name = () => { 5 // ... 6}
1// difference 2one.js 3window.name = 'Symbol卢'; 4two.js 5window.name = 'Jack李'; 6three.js 7window.name = 'Leo';

在window对象中定义全局的变量,容易污染全局的环境,在平时的工作中,多人协作,很有可能会出现小惊喜,所有要慎重慎重,再慎重

给常量赋值

1let lastName = fullName[1]; //如果fullName=[],那么fullName[1]=undefined 很容易就出问题了 2let propertyValue = Object.attr; //如果Object={},那么Object.attr=undefined

对于引用数据类型(也包括接口中返回的数据),要做好兜底(没有数据的话,给个默认值)你怎么却确定它里面一定有值??

1let lastName = fullName[1] || '' 2let propertyValue=Object.attr || 0

(1)要按强类型风格写代码定义变量的时候要指明类型,并且在变量声明之后,不要随意的去更改变量的数据类型,改着改着搞不好就出问题了

1// 假设声明三个变量a,b,c 2let a,b,c; // difference,定义变量时没有指明类型 3let a = "", b = [], c = {}; // good 4 5// difference 6let a = ""; 7... 8a = 100; // 改变了定义变量时的类型(容易出错问题哦!) 9 10let b = 5; 11... 12b = 200; // grace 定义了数据类型之后,就不要去随便的更改它

2、避免使用 == 进行逻辑判断(不要给自己的代码埋雷)

大家也都知道,js是一门弱类型的语言,表达式的赋值运算等操作也都会导致数据类型的转换,

== 表示只要值相等即为真,=== 要求不仅值相等,而且也要求类型相同,这句话相信大家也都知道

但是它们之前的运算规则是什么样的呢?咱们下一篇的js中的数据类型的时候再好好的聊聊;

使用== 有时候会达不到预期的结果,埋下隐患,来看看下面的这些情况(你品,你细品)

10 == '' // true 20 == '0' // true 3'' == 0 // true 4'' == '0' // false 5false == '0' // true 6false == 'false' // false 7false == undefined // false 8false == null // false 9null == undefined // true 10true == 1 // true

如果确定了这个变量的数据类型,那么就没必要使用 == 多巧一个等号,给程序多一份保障,又不要钱,怕啥??干就完了;判断调试的时候就使用===,那数据类型不确定咋办,,,,(小声逼逼,数据类型不确定,那就动动发财手,转换一下数据类型呗)

如果变量的数据类型不确定,那咱就手动的转换一下,让它确定

1let total = "6"; 2if(total == 6) {} // difference 3if(parseInt(total) === 6){} // grace 手动转换一下数据类型

数组

在对数组进行操作的时候,推荐优先使用ES6+中的新的语法,之前出的聊聊js中的数组

1// 数组拷贝 2// difference 3let items=['1','2','3']; 4let items2=['4','5','6']; 5for (i = 0; i < items.lenght; i++){ 6 items.push(items2[i]); 7} 8 9// grace 10const itemsCopy = [...items]; 11 12// 扩展运算符简写 13// joining arrays 14const odd = [1, 3, 5]; 15const nums = [2 ,4 , 6].concat(odd); 16// cloning arrays 17const arr = [1, 2, 3, 4]; 18const arr2 = arr.slice() 19 20// joining arrays 21const odd = [1, 3, 5 ]; 22const nums = [2 ,4 , 6, ...odd]; 23console.log(nums); // [ 2, 4, 6, 1, 3, 5 ] 24// cloning arrays 25const arr = [1, 2, 3, 4]; 26const arr2 = [...arr];
  • 使用数组成员对变量赋值时,优先使用解构赋值。
1const Arr = [1, 2, 3, 4]; 2 3// difference 4const first = Arr[0]; 5const second = Arr[1]; 6 7// grace 8const [first, second] = Arr; // 有简单的方法。肯定要用简单的方法啦

函数

函数是我们工作当中用到非常多的,但是如何写出优雅的函数呢??接下来咱就来用函数的命名,函数的入参,参数校验,函数的出参等几个方面来一起聊聊如何让你写的函数更加的优雅,来吧 come quick!!

函数的命名

函数的命名,我们首先就是需要语义化 (功能性命名,也就是说,这个函数是为干什么事情而生的),比如:返回布尔值函数应以is/can/has等单词开头,能够让人更直观的了解到这个函数的功能;获取接口中的数据使用get开头进行命名。

1let isEmpty = () => {...} 2let canCreateDocuments = () => {...} 3let hasLicense = () => {...} 4 5// 不用「否定」语法命名函数 6//difference 7let isNotSupport = () => {}; 8let canNotUpdate = () => {}; 9 10// grace 11let isSupport = () => {}; 12let canUpdate = () => {};

动作函数要以动词开头

1let sendEmailToUser = (user) => { 2 .... 3} 4let geUserInfo = (user) => { 5 .... 6} 7let setUserInfo = (user) => { 8 .... 9}

优先使用箭头函数

箭头函数相比于传统的函数(function)而言,箭头函数更简洁,并且也绑定好 了this(箭头函数不会去改变this的指向)。

1let arr [18, 19, 20, 21, 22,23,24,25] 2// commonly 3function findAge (arr, age) { 4 return arr.filter(function (num) { 5 return num === age 6 }) 7} 8// grace 是不是看着更简介优雅了 9let findAge = (arr, age)=> arr.filter(num => num === age)

函数的入参

函数的入参,是能够让使用者,在调用这个函数的时候,能够更加的清晰明了的把这个函数所需要的参数传递给函数,不容易出现,参数传递错误(参数的顺序颠倒等)一些低级,而又不好查找的问题,

1// difference 2function getImages(api, true, false); // true和false啥意思,没有个注释的话,看上去就是一脸懵逼 3// grace 4function getImages({ 5 imageApi: api, 6 includePageBackground: true, // 一目了然,知道这些true和false是啥意思 7 compress: false, 8})

接收参数

如果函数的的参数是对象,也要优先使用解构赋值,上代码

1// 假设现在的场景是获取用户的信息上的现用名,和曾用名 2// difference 3function getFullName(user) { 4 const firstName = user.firstName; 5 const lastName = user.lastName; 6} 7 8// commonly 9function getFullName(obj) { 10 const { firstName, lastName } = obj; 11} 12 13// grace 14function getFullName({ firstName, lastName }) { 15} 16 17// grace 给它个默认值 18function getFullName({firstName, lastName = '无'}) { 19} 20 21// 觉得参数的名称太长,咱再来个重命名 解构时重命名简化命名 22// grace 23function getFullName ({firstName: first, lastName: last}) { 24 25}

参数校验

更少的嵌套,不满足条件尽早 return,尽可能的减少嵌套,嵌套的层级越少,函数看着越简洁优雅,

1function test(name, sex = 1) { 2 if (!name){ // 不满足条件尽早抛出错误 3 throw new Error('没有传递name参数'); 4 } 5 // ... 6}

函数的出参

聊完了函数的入参,咱在聊聊函数的出参,在函数的出参中,首先就是要保证函数出参的数据类型是固定的,如果函数返回多个值,优先推荐优先使用对象作为返回值,而不是数组。为什么呢???因为对象作为返回值,更便于以后添加返回值,以及更改返回值的顺序,相对于数组更加的灵活,更便于扩展

1// 注意,返回参数的数据类型要是固定的, 2// difference返回了不同的数据类型 3function getResult(cont) { 4 if(count < 0) { 5 return ""; 6 } else { 7 return count * 10; 8 } 9} 10 11// grace 12function getResult(cont) { 13 if(count < 0) { 14 return -1; 15 } else { 16 return count * 10; 17 } 18} 19 20// 函数返回多个值,推荐使用对象作为函数的返回值 21// commonly 22function processInput(input) { 23 return [left, right, top, bottom]; 24} 25 26// grace 27function processInput(input) { 28 return { left, right, top, bottom }; 29} 30const { left, right } = processInput(input);

立即执行函数

立即执行函数也推荐写成箭头函数的形式。首先是因为更简洁,并且也绑定好 this(箭头函数不会去改变this的指向)。

1(() => { 2 console.log('感觉这篇文章还可以的话,欢迎点赞+关注+转发'); 3})();

优先使用函数式编程

1// difference 2for(i = 1; i <= 10; i++) { 3 a[i] = a[i] +1; 4} 5// grace 6let b = a.map(item => ++item) //是不是更简洁了

函数中过多的采用if else ..

注:为了方便大家看优化格式,这是随便使用了a来记性演示语法结构(我词穷了)

1// commonly 2if (a === 1) { 3 //... 4} else if (a ===2) { 5 // ... 6} else if (a === 3) { 7 //... 8} else { 9 //... 10} 11 12// 一般 13switch(a) { 14 case 1: 15 //.... 16 case 2: 17 //.... 18 case 3: 19 //.... 20 default: 21 //.... 22} 23 24// grace ===》》》 Object 25const fruit = { 26 1: ['1', '11'], 27 2: ['2', '22'], 28 3: ['3', '33'] 29 }; 30let test = (a) => { 31 return fruit[a] || []; 32} 33 34// grace ===》》》 Map 35const fruit = newMap() 36 .set('张三', ['张三丰', '张三力']) 37 .set('李四', ['李思维', '李素丽']) 38let test = (a) => { 39 return fruit.get(a) || []; 40} 41 42// grace ===》》》filter 43const fruits = [ 44 { name: '张三', work: 'js' }, 45 { name: '李四', work: 'php' }, 46 { name: '王五', work: 'java' }, 47]; 48let test = (a) => { 49 return fruits.filter(item => item.name === a); 50} 51 52// grace===》》》策略模式 53let handler = { 54 1: () => { 55 //.... 56 }, 57 2: () => { 58 //.... 59 }, 60 3: () => { 61 //.... 62 }, 63 default: () => { 64 //.... 65 } 66} 67handler[a]() || handler['default']()

温馨小提示

一个函数完成一个独立的功能,不要一个函数混杂多个功能,在项目开发中有一条非常重要的原则【单一原则】所谓的单一原则就是,一个函数(文件),只做一件事情,在开发当中,没有那个项目是开发完成之后,就结束了。需要不断的更新,维护,那么单一原则,就是为了方便开发,和维护的,不要让一个函数“又当爹,又当妈”,这样代码的耦合性太高了,不好维护

其他

在if中判断数组长度的判断

1// difference 2if (arr.length !== 0) { 3 //... 4} 5 6// grace 7if (arr.length) { 8 //... 9} 10 11// difference 12if (arr.length === 0) { 13 //... 14} 15 16// grace 17if (!arr.length) { 18 //... 19}

逻辑运算符

1if (a === 1) { 2 b() 3} 4//可以写成 5a === 1 && b() 6 7const arr = [1,2,3]; 8if(!arr.length){ 9 b() 10 } 11//可以写出 12arr.length || b() 13 14// &&判断依赖的键是否存在,防止报错'xxx of undfined' 15let user = { 16 name: 'Symbol卢', 17 age: 18, 18 children: { 19 name: '小Symbol卢' 20 } 21} 22let childrenName = user.children && user.childre.name

能使用三目运算符(三元运算符)就使用,留着舍不得用,要留着过年用嘛

1// difference 2const a = ''; 3let b; 4if( a === '' ){ 5 b = 'no' 6} else { 7 b = 'ok' 8} 9 10const a = '' 11let b = a ? 'no' : 'ok'; // 'ok'

判断元素是否存在,当类型为undefined或null或空的string(' ')或0时,可以直接使用if(a)/if(!a)的形式。当类型为array或object时,就可以使用if(a instanceof Array)或if(a instanceof String)的形式进行判断,这里也送上笔者之前写的一个关于数据类型判断的一个函数

1/** 2 * @description: 数据类型的检测的第二种方式 3 * @param {any} data 要检测数据类型的变量 4 * @return {string} type 返回具体的类型名称【小写】 5 */ 6export const isTypeOf = (data) => { 7 return Object.prototype.toString.call(data).replace(/\[object (\w+)\]/, '$1').toLowerCase() 8}

对于for循环优先使用命令式编程

1// difference 2let result=[] 3let numberArr=[1,2,3,4,5,6] 4for(i = 1; i <= 10; i++) { 5 if(numberArr[i]>4){ 6 result.push(numberArr[i]) 7 } 8}

优先的使用命令式编程,例如:find、some、every、map、filter,各种用法可以参考:之前出的聊聊js中的数组

使用 Array.includes 来处理多重 || 条件

1// difference 2if (a === 1 || a === 2 || a === 3 || a === 4) { 3 //... 4} 5// grace 6let arr = [1, 2, 3, 4] 7if (arr.includes(a)) { 8 //... 9}

使用 Array.every 和 Array.some 来处理全部/部分满足条件

1// grace 2const users = [ 3 { name: '张三', sex:1 }, 4 { name: '李四', sex:2 }, 5 { name: '王五', sex:1 } 6 ]; 7function test() { 8 // 条件:(简短形式)所有的用户都必须是女 9 const isAllGirl = users.every(item => item.sex === 1); 10 11 // 条件:至少一个用户是男的 12 const isAnyMan = users.some(item => item.sex === 2); 13 14}

使用正则表达式

1const imgType ='jpg' 2if(imgType === 'jpg' || imgType === 'png' || imgType === 'gif'){ 3 console.log('is image') 4} 5 6// 使用match匹配正则表达式 7const imgType='jpg' 8if(imgType.match(/.*?(gif|png|jpg)/gi)){ 9 console.log('is image') 10}

连接字符串

1let name = 'Symbol' 2let message = 'Hello,I\'m' + name + 'take care '// 采用传统加号,看着很冗余,且容易出错 3// 艾玛,模板字符香,真想 4let message = `Hello,I'm ${name} take care `

总结

在自己完成某一个功能之后,问问自己,除了自己当前的写法,还有没有其他更简洁的写法呢???

项目推荐 vue-pure-admin

简介:vue-pure-admin是一个免费开源的中后台模板,使用了最新的 vue3 , vite2 , TypeScript ,Element-Plus 等主流技术开发,开箱即用的中后台前端解决方案 项目预览地址 vue-pure-admin

GitHub地址: vue-pure-admin

1.png

2.png

3.png

历史好文

  1. 聊聊js中的数组
  2. 用大白话轻松搞定正则(上)
  3. 用大白话轻松搞定正则(下)
  4. 一起学重绘和回流
  5. js垃圾回收机制原理给你聊的明明白白
  6. ES11来了,不进来看看嘛
  7. 秒懂js作用域与作用域链

结束语

以上就是这篇文章的全部内容,希望对大家有帮助,这里不用打赏的哈大家可以给个赞👍(赞又不要钱),同样也 欢迎大家转发

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

如何优雅的写 css 代码

CSS(全称CascadingStyleSheets,层叠样式表)为开发人员提供声明式的样式语言,是前端必备的技能之一,基于互联网上全面的资料和简单易懂的语法,CSS非常易于学习,但其知识点广泛且分散,很难做到精通,在我们日常开发中,常常忽视了CSS代码的质量,很容易写出杂乱无章的CSS文件。

java 性能优化:35 个小细节,让你提升 java 代码的运行效率

前言代码 优化 ,一个很重要的课题。可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用,但是,吃的小虾米一多之后,鲸鱼就被喂饱了。代码优化也是一样,如果项目着眼于尽快无BUG上线,那么此时可以抓大放小,代码的细节可以不精打细磨;但