当一个函数变成两个函数以后,明显对于代码的理解上来说有了非常大的提升,阅读的时候由于其单一性,因此并不会给理解带来困扰;
上面说的参数数量其实都是固定的,那么还有一种函数或者方法,它的参数数量是不固定的,比如
const total = sum(1, 2, 3, 4, 5, 6);
const totalNext = sum(10, 11, 12, 14);
function sum(…numbers){
let total = 0;
for(let number of numbers){
total += number;
}
return total;
}
通过阅读,我们知道这是一个求和的函数,并且参数的数量也是不固定的,那么这种函数需要优化吗,我个人认为是需要的,因为这种函数并不符合我们上面说的最小参数数量规则,那么怎么改,其实很简单
const total = sum([1, 2, 3, 4, 5, 6]);
const totalNext = sum([10, 11, 12, 14]);
简单的就是将其变成一个数组,那么参数的数量就会变得固定,有且只有一个,这种就会变得相对合理一些,但是可能会有小伙伴问,上面那种不行吗?看着也很清晰,很合理,其实也行,不要忘记干净代码的核心就是代码结构清晰,易于理解,容易维护,只要团队成员一致觉得可行,那么其实就是最合理的,所谓的规则就是在为团队服务,并不是一成不变的东西;
==============================================================
在函数体的编码过程中,有一些我个人认为是非常有意思的注意点,这些注意点可以帮助我们更好的写出干净的代码;
比如某些情况下,我们可能需要对一个对象进行加工处理,之后再将这个对象返回,先看一个最不推荐的方式
// 不推荐
function createId(user){
user.id = “oliver”
// …其他一些操作
}
createId({name: “Oliver”})
这种为什么不推荐,因为在这个函数里面对用户这个对象进行了操作,这种操作从名字上看就是不可预知的,对于未知操作我个人非常不推荐,因为会造成不可控的结果,稍微好一点的,那么会从函数的名字上会有体现,比如,明确需求是给用户添加一个id,那么代码可能如下:
// 相对合理些
function addId(user){
user.id = “oliver”
}
addId({name: “Oliver”})
从名字上看,我们能知道这个函数的作用就是为用户添加一个id,因此和第一种比,这种函数我们是能预知到结果的,因此相对合理些,那么有没有更合理的方式,那肯定有的
// 个人觉得最优
class User{
constructor(name){
this.name = name;
}
addId(){
this.id = “oliver”;
}
}
const customer = new User(“Oliver”);
customer.addId();
跟上面两种相比,是不是更加合理一些,我们实力化了一个用户,并且通过执行addId这个方法为customer添加了id这个属性,不管使用代码的结构上还是理解上都相对很清晰,因此,我个人认为这种方法相对最优;
我想有一点肯定所有的小伙伴都会同意的,那就是函数体的代码长度,如果一个函数体的长度有个几百行上千行,换谁看了都会想给写的人突突突一下,那怎么理解代码长度呢?换个专业点的说法,就是代码的层次,结构清晰,功能单一,这样写出来的函数长度往往是可控的,足够的小巧和精简,下面看一个例子:
function renderContent(renderInfomation) {
const element = renderInfomation.element;
if (element === “script” || element === “SCRIPT”) {
throw new Error(“异常”);
}
let partialOpeningTag = “<” + element;
const attributes = renderInfomation.attributes;
for (const attribute of attributes) {
partialOpeningTag =
partialOpeningTag +
" " +
attribute.name +
“='” +
attribute.value +
“'”;
}
const openingTag = partialOpeningTag + “>”;
const closingTag = “</” + element + “>”;
const content = renderInfomation.content;
const template = openingTag + content + closingTag;
const rootElement = renderInfomation.root;
rootElement.innerHTML = template;
}
这段代码相信只要耐心看完就一定可以理解,简单的说就是一个创建标签的函数,从之前的规范性干净角度上来看,是符合我们之前说的一些规则的,但是个人觉得这段代码还不足够干净,为什么?因为我们需要花费一定的精力去阅读理解这段代码,而干净的代码要尽可能的让代码易于理解,那么如何优化呢,简单的说,就是拆分,让函数的功能变的单一:
function renderContent(renderInfomation) {
const element = renderInfomation.element;
const rootElement = renderInfomation.root;
validateElementType(element);
const content = createRenderableContent(renderInfomation);
renderOnRoot(rootElement,content)
}
拆分后大致如上,函数的以不同的功能区域为边界进行拆分,将一个区域拆成一个函数,大致被分为了三步:
-
验证标签;
-
创建标签内部;
-
将标签插入到根节点;
是不是从结构上,代码量上都变得更易阅读了,这就是上面说的,以单一功能为边界进行函数拆封;可能有小伙伴还是不理解什么是单一功能,再举个例子吧,登录操作往往包含了校验,发送请求,那从功能上讲是不是就可以拆成校验一个函数,发送请求一个函数,这样应该能理解了吧;
除了上面说的以功能,操作为边界进行拆分外,还有一些其他的拆分规则可以帮助我们使得代码的长度得到精简,易于阅读;
公共函数的提取(DIY原则)
就是我们常说的DIY原则,“Don’t Repeat Yourself”,什么意思呢?当多个函数内部使用到了相同或者相似的代码时,那么对于这一部分代码就可以进行拆分,拆分后不管是从代码的长度,还是维护的角度都使得代码得到了提升,比如
function saveUser(user){
if(!user.email.includes(“@”)){
// 代码
}
}
function getUser(user){
if(!user.email.includes(“@”)){
// 代码
}
}
在这两段代码内,都存在一个校验参数user上email属性的过程,对于这一个过程两者完全一致,那么对于这种完全一致的代码我们就可以提取公共函数
function isEmail(email){
return email.includes(“@”);
}
function saveUser(user){
if(!isEmail(user.email)){
// 代码
}
}
function getUser(user){
if(!isEmail(user.email)){
// 代码
}
}
提取后,公共代码得到了统一的维护与管理,并且一旦哪天发现代码编写错误有BUG,也可以直接修改公共函数,而不需要一个一个的修改;
(PS:其他规则待补充)
我们说到,拆分的根本目的是为了让我们的代码变的干净,使其更易理解,更易阅读,更易维护等等,因此拆分前不能忘记我们的初衷,简单的总结了一下,大致有以下几种情况可以不拆分我们的函数或者方法:
仅整合,重组的操作
什么意思呢?直接看例子吧
function saveUser(username,password){
const user = buildUser(username,password);
// 针对用户的其他操作…
}
function buildUser(username,password){
return {
username,
password
}
}
个人觉得这种就是典型的过度拆分,因为没有任何意义,即使不拆分会影响我们阅读代码吗,我个人感觉不会
function saveUser(username,password){
const user = {
username,
password
};
// 针对用户的其他操作…
}
对吧,上面那种由于多了一个函数,反而我们需要花更多的时间去阅读理解;
查询新函数花费成本高
找到新函数的时间比阅读花费的时间更长,这个也好理解吧,从字面意思就可以理解,正如上文说的,我们拆分函数的目的是为了让函数体更干净,更易于阅读;
一旦过度拆分就会造成一个后果,我们是不是需要去寻找新函数,一旦新函数的寻找时间付出和收益不再成正比,那么我个人认为就不再合适拆分,或者说至少拆分后的位置不合理,这种那么就需要修改函数位置,或者让函数不再拆分就放在原来的位置即可;
无法合理命名拆分的函数
对于这种函数,我个人认为也不大适合拆分,什么意思呢?简单的说就是我们从原函数中拆分出来了一个段代码,但是针对这一段代码我们无法找到一个合适的名字来概括这段内容,或者说我们的函数名在阅读者阅读代码的时候无法快速的给人概括性的说明,举个例子吧
function createUser(username,password){
const user = buildUser(username,password);
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
自己不成体系的自学效果低效漫长且无助。**
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-tFcUh1GF-1715722052518)]
[外链图片转存中…(img-IsrMyDD5-1715722052519)]
[外链图片转存中…(img-nzVQPty9-1715722052519)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!