黑马程序员技术交流社区
标题: 如何让你的代码更优雅 [打印本页]
作者: charcoal 时间: 2021-5-17 09:46
标题: 如何让你的代码更优雅
前言:
你有没有骂过“前任”的代码?你的代码有没有被吐槽过?没有注释,命名随意,没有封装,结构混乱,一个页面几千行。。。。
如何写出优雅的代码,让自己不被吐槽,让人羡慕,接下来咱就一起聊聊如何写出优雅的代码,如果大家有更好的写法和经验,欢迎在评论区留言,一起学习
什么样的代码是优雅的代码:
咱先聊聊,什么样的代码是优雅的代码,在我看来,优雅的代码包括以下方面,首先就是代码的简洁,能够使用一行代码解决的,就不要写两行及以上,其次就是便于阅读,代码不仅仅是用来让机器(服务器,浏览器)来运行的,而是需要用人来编写,维护的,可能是自己,也可能是现在的同事,未来的同事,这个就是代码的可维护性,还有一个就是我们很关注的就是性能,就比如我们经常写的循环,在满足业务功能条件的时候,能少一次循环就少一次循环,还有就是不再使用的引用类型的数据,要及时手动的进行内存的释放,(虽然有垃圾回收机制),但是早一点释放内存是不是更好呢
注释:
注释,写代码少不了注释,尤其是优雅的代码,更少不了注释;注释是给人看的,可能是自己,也可能是同事以及未来的同事看的,(这几句话说了好多遍了),那么我们为什么要写注释,以及该怎么样去写注释呢?,接下来咱就先来聊聊注释
如何使用注释?
通用的规则是在代码不清晰时需要添加注释,个人觉得包含以下几个方面:
- 难于理解的代码添加注释(逻辑比较复杂,嵌套层级比较多,传递参数不明显等)
2. 可能被误认为错误的代码(没有按照正常套路出牌的代码 3. 数据的状态(就拿订单状态来说,订单可能有多钟状态,此时在写这段的叶落逻辑的时候,就把不同的状态表示的含义写上去,以后的维护,或者是有新人接收这个项目的时候能够更快的上手) 4. 其他注释(文档注释,变量注释,函数注释)
1、文档注释
简单描述当前js文件作用,是页面js逻辑处理,还是公共的方法等
如果是vue项目则是描述出当前vue文件的作用,
2、变量注释
注明变量是用来做什么的,来进行语义化的命名,需要注释的则加上注释
[JavaScript] 纯文本查看 复制代码
// difference
let uName = 'Symbol卢'; // 虽然用了驼峰,但是简写严重。无法直观看出变量的含义
// grace
let userName = 'Symbol卢'; // 语义化命名,不能过于缩写
3、函数的注释
参数注释包括参数的数据类型,参数的命名语义化,返回参数注释包括了默认值,已经返回参数的数据类型
例如:
[JavaScript] 纯文本查看 复制代码
/**
* @description: 数据类型的检测的第二种方式
* @param {any} data 要检测数据类型的变量
* @return {string} type 返回具体的类型名称【小写】
*/
export const $typeOf = (data) => {
return Object.prototype.toString.call(data).replace(/\[object (\w+)\]/, '$1').toLowerCase()
}
可以在vscode的插件市场,下载koroFileHeader 进行安装,可以一键生成注释格式
变量
定义变量的准则:
变量用小写(声明变量用let),常量用大写(声明常量用const),变量命名语义化,指定变量的数据类型,避免使用太多的全局变量,先声明,后使用。
1、let const 取代 var
[JavaScript] 纯文本查看 复制代码
// difference
var myLove = 'My love is Code';//没有使用const进行命名,且常量名称没有全部大写
// grace
const MY_LOVE = 'My love is Code';
使用 var 关键字 定义的 常量 是可以变化的,也就是,我们定义一个常量之后,还可以给它赋值来改变这个常量,然后按照我们在程序当中的规范,在声明一个常量之后,这个常量在整个程序也就全局中是不能够再被改变的,所以声明一个常量,要使用关键字 const 来声明常量,并且通常常量的名称都是大写的,并且语义化,让人看到这个常量的时候,就知道这个常量是干什么的
刚好聊到了常量声明中的字符串,那咱再看看,在使用字符串常量的时候,要注意哪些规范,上代码
[JavaScript] 纯文本查看 复制代码
//要注意。静态字符串一律使用单引号或反引号(模板字符串),不使用双引号,动态字符串使用反引号,拒绝使用 + 进行字符串的拼接
// difference
const name = "Symbol卢";
const say = 'My name is' + name + 'and I love FE';
// grace
const NAME = 'Symbol卢';
const b = `My name is ${ NAME } and I love FE`;
定义变量
定义局部的变量的时候使用let ,定义全局的变量的时候使用var,要记住一个原则就是,变量的声明要只在其声明的代码块中有效
[JavaScript] 纯文本查看 复制代码
// difference
one.js
window.name = 'Symbol卢';
two.js
window.name = 'Jack李';
three.js
window.name = 'Leo';
在window对象中定义全局的变量,容易污染全局的环境,在平时的工作中,多人协作,很有可能会出现小惊喜,所有要慎重慎重,再慎重
给常量赋值
[JavaScript] 纯文本查看 复制代码
let lastName = fullName[1]; //如果fullName=[],那么fullName[1]=undefined 很容易就出问题了
let propertyValue = Object.attr; //如果Object={},那么Object.attr=undefined
对于引用数据类型(也包括接口中返回的数据),要做好兜底(没有数据的话,给个默认值)你怎么却确定它里面一定有值??
[JavaScript] 纯文本查看 复制代码
let lastName = fullName[1] || ''
let propertyValue=Object.attr || 0
(1)要按强类型风格写代码定义变量的时候要指明类型,并且在变量声明之后,不要随意的去更改变量的数据类型,改着改着搞不好就出问题了
[JavaScript] 纯文本查看 复制代码
// 假设声明三个变量a,b,c
let a,b,c; // difference,定义变量时没有指明类型
let a = "", b = [], c = {}; // good
// difference
let a = "";
...
a = 100; // 改变了定义变量时的类型(容易出错问题哦!)
let b = 5;
...
b = 200; // grace 定义了数据类型之后,就不要去随便的更改它
2、避免使用 == 进行逻辑判断(不要给自己的代码埋雷)
大家也都知道,js是一门弱类型的语言,表达式的赋值运算等操作也都会导致数据类型的转换,
== 表示只要值相等即为真,=== 要求不仅值相等,而且也要求类型相同,这句话相信大家也都知道
使用== 有时候会达不到预期的结果,埋下隐患,来看看下面的这些情况(你品,你细品)
[JavaScript] 纯文本查看 复制代码
0 == '' // true
0 == '0' // true
'' == 0 // true
'' == '0' // false
false == '0' // true
false == 'false' // false
false == undefined // false
false == null // false
null == undefined // true
true == 1 // true
如果确定了这个变量的数据类型,那么就没必要使用 == 多巧一个等号,给程序多一份保障,又不要钱,怕啥??干就完了;判断调试的时候就使用===,那数据类型不确定咋办,,,,(小声逼逼,数据类型不确定,那就动动发财手,转换一下数据类型呗)
如果变量的数据类型不确定,那咱就手动的转换一下,让它确定
[JavaScript] 纯文本查看 复制代码
let total = "6";
if(total == 6) {} // difference
if(parseInt(total) === 6){} // grace 手动转换一下数据类型
数组
在对数组进行操作的时候,推荐优先使用ES6+中的新的语法
[JavaScript] 纯文本查看 复制代码
// 数组拷贝
// difference
let items=['1','2','3'];
let items2=['4','5','6'];
for (i = 0; i < items.lenght; i++){
items.push(items2);
}
// grace
const itemsCopy = [...items,...items2];
// 扩展运算符简写
// joining arrays
const odd = [1, 3, 5];
const nums = [2 ,4 , 6].concat(odd);
// cloning arrays
const arr = [1, 2, 3, 4];
const arr2 = arr.slice()
// joining arrays
const odd = [1, 3, 5 ];
const nums = [2 ,4 , 6, ...odd];
console.log(nums); // [ 2, 4, 6, 1, 3, 5 ]
// cloning arrays
const arr = [1, 2, 3, 4];
const arr2 = [...arr];
[JavaScript] 纯文本查看 复制代码
const Arr = [1, 2, 3, 4];
// difference
const first = Arr[0];
const second = Arr[1];
// grace
const [first, second] = Arr; // 有简单的方法。肯定要用简单的方法啦
函数
函数是我们工作当中用到非常多的,但是如何写出优雅的函数呢??接下来咱就来用函数的命名,函数的入参,参数校验,函数的出参等几个方面来一起聊聊如何让你写的函数更加的优雅,来吧 come quick!!
函数的命名:
函数的命名,我们首先就是需要语义化 (功能性命名,也就是说,这个函数是为干什么事情而生的),比如:返回布尔值函数应以is/can/has等单词开头,能够让人更直观的了解到这个函数的功能;获取接口中的数据使用get开头进行命名。
[JavaScript] 纯文本查看 复制代码
let isEmpty = () => {...}
let canCreateDocuments = () => {...}
let hasLicense = () => {...}
// 不用「否定」语法命名函数
//difference
let isNotSupport = () => {};
let canNotUpdate = () => {};
// grace
let isSupport = () => {};
let canUpdate = () => {};
动作函数要以动词开头
let sendEmailToUser = (user) => {
....
}
let geUserInfo = (user) => {
....
}
let setUserInfo = (user) => {
....
}
优先使用箭头函数
箭头函数相比于传统的函数(function)而言,箭头函数更简洁,并且也绑定好 了this(箭头函数不会去改变this的指向)。
[JavaScript] 纯文本查看 复制代码
let arr [18, 19, 20, 21, 22,23,24,25]
// commonly
function findAge (arr, age) {
return arr.filter(function (num) {
return num === age
})
}
// grace 是不是看着更简介优雅了
let findAge = (arr, age)=> arr.filter(num => num === age)
函数的入参,是能够让使用者,在调用这个函数的时候,能够更加的清晰明了的把这个函数所需要的参数传递给函数,不容易出现,参数传递错误(参数的顺序颠倒等)一些低级,而又不好查找的问题,
[JavaScript] 纯文本查看 复制代码
// difference
function getImages(api, true, false); // true和false啥意思,没有个注释的话,看上去就是一脸懵逼
// grace
function getImages({
imageApi: api,
includePageBackground: true, // 一目了然,知道这些true和false是啥意思
compress: false,
})
接收参数
如果函数的的参数是对象,也要优先使用解构赋值,上代码
[JavaScript] 纯文本查看 复制代码
// 假设现在的场景是获取用户的信息上的现用名,和曾用名
// difference
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
}
// commonly
function getFullName(obj) {
const { firstName, lastName } = obj;
}
// grace
function getFullName({ firstName, lastName }) {
}
// grace 给它个默认值
function getFullName({firstName, lastName = '无'}) {
}
// 觉得参数的名称太长,咱再来个重命名 解构时重命名简化命名
// grace
function getFullName ({firstName: first, lastName: last}) {
}
参数校验
更少的嵌套,不满足条件尽早 return,尽可能的减少嵌套,嵌套的层级越少,函数看着越简洁优雅,
[JavaScript] 纯文本查看 复制代码
function test(name, sex = 1) {
if (!name){ // 不满足条件尽早抛出错误
throw new Error('没有传递name参数');
}
// ...
}
函数的出参
聊完了函数的入参,咱在聊聊函数的出参,在函数的出参中,首先就是要保证函数出参的数据类型是固定的,如果函数返回多个值,优先推荐优先使用对象作为返回值,而不是数组。为什么呢???因为对象作为返回值,更便于以后添加返回值,以及更改返回值的顺序,相对于数组更加的灵活,更便于扩展
[JavaScript] 纯文本查看 复制代码
// 注意,返回参数的数据类型要是固定的,
// difference返回了不同的数据类型
function getResult(cont) {
if(count < 0) {
return "";
} else {
return count * 10;
}
}
// grace
function getResult(cont) {
if(count < 0) {
return -1;
} else {
return count * 10;
}
}
// 函数返回多个值,推荐使用对象作为函数的返回值
// commonly
function processInput(input) {
return [left, right, top, bottom];
}
// grace
function processInput(input) {
return { left, right, top, bottom };
}
const { left, right } = processInput(input);
立即执行函数
立即执行函数也推荐写成箭头函数的形式。首先是因为更简洁,并且也绑定好 this(箭头函数不会去改变this的指向)。
[JavaScript] 纯文本查看 复制代码
(() => {
console.log('感觉这篇文章还可以的话,欢迎点赞+关注+转发');
})();
优先使用函数式编程
[JavaScript] 纯文本查看 复制代码
// difference
for(i = 1; i <= 10; i++) {
a = a +1;
}
// grace
let b = a.map(item => ++item) //是不是更简洁了
总结
在自己完成某一个功能之后,问问自己,除了自己当前的写法,还有没有其他更简洁的写法呢???
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |