JavaScript 代码不嵌套主义
文章目录
- 前言
- 一、何为嵌套代码
- 二、避免嵌套
- 1.提炼抽取
- 2.反转排列
- 总结
前言
看过不少过度嵌套的代码, 我真正意识到问题的严重性是刚入职那会, 我在一个老项目里看到了40个连续的else if
, 套了6层的if
, for
和forEach
, 因为我们并没有做什么限制代码嵌套的提前约定.
呃, 那之后认识到会写代码
和代码写得好
完全是两种概念, 能够实现复杂的需求也并不能说明代码写得好, 开始注重代码结构方面.
事实是, 很多时候需要编写的逻辑本身就很恶心, 乍看之下, 堆页岩般的判定嵌套里似乎每一层都是必要的, 也只能说尽量让它看起来不那么恶心.
嗯, 比如少来几次Tab
.
一、何为嵌套代码
嵌套代码是在函数内部添加更深层级的代码块, 放在javascript
里, 常用的嵌套手段都包含符号’{
‘, 那么对于一个代码块, 刨除平级的情况, 其内部的’{
'越多就说明这个代码块的嵌套深度越大.
也就是: 禁止套娃.
对于以下代码, 它的嵌套深度为1:
function fun1 () {console.log(1);
}
而如果在内部加上if
语句, 其深度将变为2:
function fun1 () {if (true) {console.log(1);}
}
而如果再加一个循环进去, 深度将变为3:
function fun1 () {if (true) {for (let i = 0; i < 5; i++) {console.log(1);}} else {console.log(2);}
}
而…
好的各位, 我最多最多就到这了, 再套下去我就要开始觉得恶心了.在这里可能没有那么直观, 而这段代码放在编辑器里, console.log
前面已经有三道竖线了, 光是tab
提行就已经开始不舒服了.
在三层嵌套以上, 你所做的一切就不再是一套单一的算法, 这已经开始逐渐演变为多个算法的组合了, 是可以做一些封装抽离而最好不要就这样混写在一起.
实战中三层嵌套绝对连半数以下的计算都处理不了, 那如果还有逻辑没编写呢.
二、避免嵌套
1.提炼抽取
提炼(Extraction)
, 我一般管这叫抽离, 当然, 不一定要抽到外面, 只要能维持嵌套深度处于稳定的水平就好(不过函数内实在不能在消减嵌套深度那还是抽到外面形成另外一个函数吧).
比如这段嵌套:
function fun1() {const arr = [1, 2, 3, 4]if (arr.length = 4) {arr.forEach((ele) => {if (a === 4) {console.log(4);}});}
}fun1();
可以改为这样:
function fun1() {const arr = [1, 2, 3, 4]const xxx = (a) => {if (a === 4) {console.log(4);}}if (arr.length = 4) {arr.forEach(xxx);}
}fun1();
嵌套深度由4减小为3.
原理十分明了, 就好像在原生环境获取DOM, 有的人喜欢这样:
function change() {document.querySelector("#scar").style.display = 'none';
}
有的人喜欢:
function change() {const scar = document.querySelector("#scar");scar.style.display = 'none';
}
抽离提炼就类似于将前者转化为了后者.
封装axios
也是一样的道理(不过那更多还是为了避免接口变动导致的被动局面).
2.反转排列
反转(Inversion)
, 对于判定语句, 把正面条件排在负面条件前通常会需要更多的判定, 所以改为优先处理负面条件.
先把正面条件放前面:
function justice(e) {if(e.length > 5) {for(let i = 0; i < e.length; i++) {console.log(e);}} else if (e.length === 2){return 2;} else {return false}
}
但是如果先进行负面条件判定:
function justice(e) {if(e.length === 2) {return 2;} else if (e.length < 5) { // 这里也可以另起一个if, 不过这样可以节约一行 )return false;} for(let i = 0; i < e.length; i++) {console.log(e);}
}
可以看到现在深度层级由3减小到2.
这种优化方法需要先把少数, 需要特殊处理的情况在前面解决完及时退出, 剩下的多数情况就可以不放在判定语句中.
而在这个过程中, 需要把最特殊, 且不将其他特殊情况包含在内的情况写在前面, 越特殊, 越提前处理, 此处e.length === 2
为最特殊, 而e.length < 5
这个特殊情况将e.length === 2
包含在内, 所以应当第二个处理.
我在前面也写过这种做法, 将判定嵌套改为平次的卫语句, 称作validation gatekepping
, 感兴趣的话可以去看这篇:
JavaScript 如何简化代码里的多级判定?
不过还可以在平次判定这个基础上使用这个技巧, 我们把负面情况放在靠前的平次判定处理, 如果处理中途出现过多嵌套, 那就提炼抽离, 把正面条件放最后:
function justice(e) {if(e.length === 2) {return 2;}if(e.length === 3) {return 3;}if (e.length < 5) {return false;} for(let i = 0; i < e.length; i++) {console.log(e);}
}
截取最近项目里的代码作为例子, 现在有两个world, 一个新一个旧, 如果需要让旧world的视图更新, 那么需要将新world的world.webglGroup.children
内的元素部分替换, 其他除world.frameInfo
外也要全替换.
async changeWorld(oldFrame, newWorld) {for (const key in newWorld) {if (key === 'frameInfo') {} else if (key === 'webglGroup') {for (const pro in newWorld[key]) {if (pro === 'children') {this.worldList[oldWorldIndex][key][pro] = this.worldList[oldWorldIndex][key][pro].filter((ele) => { return ele.type !== 'Group' });this.worldList[oldWorldIndex][key][pro].push(...newWorld[key][pro].filter((ele) => { return ele.type === 'Group' }));} else {this.worldList[oldWorldIndex][key][pro] = newWorld[key][pro];}}} else {this.worldList[oldWorldIndex][key] = newWorld[key];}}
}
以上是初版, 现在用Extraction
提炼和Inversion
反转去尝试降低嵌套深度:
先把world.webglGroup.children
局部替换的代码提炼为replace
,
已知world.frameInfo
不需要替换, 那么正常的负面条件写法应当为key === 'frameInfo'
, 但即便如此key === 'frameInfo'
和key === 'webglGroup'
也是必须用else if
处理的, 如果改成平次if
又不能终止执行, 那么这两个特殊条件在一轮循环中都会被执行.
本着要把正面条件处理方案
写最后的原则, 直接在最后一个特殊条件不满足(按照上文所述写法, 最后一个特殊条件不满足说明前面所列特殊条件均不满足)时执行正面条件处理方案
.
else if (key !== 'frameInfo') {this.worldList[oldWorldIndex][key] = newWorld[key];
}
async changeWorld(oldFrame, newWorld) {let oldWorldIndex = this.worldList.findIndex((w) => w.frameInfo.frame === oldFrame);const replace = () => {this.worldList[oldWorldIndex][key]['children'] = this.worldList[oldWorldIndex][key]['children'].filter((ele) => { return ele.type !== 'Group';});this.worldList[oldWorldIndex][key]['children'].push(...newWorld[key]['children'].filter((ele) => { return ele.type === 'Group';}));}for (const key in newWorld) {if (key === 'webglGroup') {replace(key);} else if (key !== 'frameInfo') {this.worldList[oldWorldIndex][key] = newWorld[key];}}return this.worldList[oldWorldIndex];
}
只是判定需求不同罢了.
上面这种写法是在所有负面条件不满足时执行正面条件处理方案
.
前面反转的例子是在任意负面条件不满足时结束执行
.
但遵循两种优化手段的原则都可以实施优化.
总结
–
相关文章:
JavaScript 代码不嵌套主义
文章目录前言一、何为嵌套代码二、避免嵌套1.提炼抽取2.反转排列总结前言 看过不少过度嵌套的代码, 我真正意识到问题的严重性是刚入职那会, 我在一个老项目里看到了40个连续的else if, 套了6层的if, for和forEach, 因为我们并没有做什么限制代码嵌套的提前约定. 呃, 那之后认…...
使用默认参数的4大要点
概述 默认参数是C中新增的特性。在C中,可以为函数的参数指定默认值。调用函数时,如果没有指定实参,则自动使用默认参数。默认参数的基本语法这里就不作介绍了,下面重点介绍使用默认参数的一些知识要点。 基本规则 1、当函数中某个…...
Linux文件系统中的硬链接及常见面试题
如果能对inode的概念有所了解,对理解本文会有所帮助。如果对inode的概念不太清楚也没有关系,我们会捎带介绍一下。在文件系统的实现层面,我们可以认为包含两个组件:一个是包含数据块的池子,池子中的数据块是等大小的&a…...
opencv-StereoBM算法
原理解释目前立体匹配算法是计算机视觉中的一个难点和热点,算法很多,但是一般的步骤是:A、匹配代价计算匹配代价计算是整个立体匹配算法的基础,实际是对不同视差下进行灰度相似性测量。常见的方法有灰度差的平方SD(squ…...
图像分类竞赛进阶技能:OpenAI-CLIP使用范例
OpenAI-CLIP 官方介绍 尽管深度学习已经彻底改变了计算机视觉,但目前的方法存在几个主要问题:典型的视觉数据集是劳动密集型的,创建成本高,同时只教授一组狭窄的视觉概念;标准视觉模型擅长于一项任务且仅擅长于一项任务,并且需要大…...
Metasploit框架基础(一)
文章目录前言一、基础认知二、批量POC/EXP的构想三、poc检测框架的简单实现四、xray五、Meatsploit框架参考前言 Metasploit 一款渗透测试框架漏洞利用的集合与构建和定制满足你的需求的基础漏洞利用和验证的工具 这几个说法都是百度或者官方文档中出现的手法,说…...
pytorch零基础实现语义分割项目(二)——标签转换与数据加载
数据转换与加载项目列表前言标签转换RGB标签到类别标签映射RGB标签转换成类别标签数据数据加载随机裁剪数据加载项目列表 语义分割项目(一)——数据概况及预处理 语义分割项目(二)——标签转换与数据加载 语义分割项目&#x…...
python(8.5)--列表习题
目录 一、求输出结果题 二、计算列表元素个数 三、查找是否存在某元素 四、删除某元素 五、如何在列表中插入元素 六、如何从列表中删除重复的元素 七、 如何将列表中的元素按照从小到大的顺序排序 八、从列表中删除重复的元素 九、大到小的顺序排序 一、求输出结…...
rt-thread pwm 多通道
一通道pwm参考 https://blog.csdn.net/yangshengwei230612/article/details/128738351?spm1001.2014.3001.5501 以下主要是多通道与一通道的区别 芯片 stm32f407rgt6 1、配置PWM设备驱动相关宏定义 添加PWM宏定义 #define BSP_USING_PWM8 #define BSP_USING_PWM8_CH1 #d…...
C语言练习 | 初学者经典练习汇总
目录 1、下面代码输出多少,为什么? 2、你要好好学习么? 3、一直写代码, 4、两个数求最大值 5、输入1-5输出工作日,输入6-7输出休息日,其他输入错误 6、写一个输入密码的代码 7、怎么样当输入数字时候…...
华为OD机试 - 自动曝光(Python) | 机试题算法思路 【2023】
最近更新的博客 华为OD机试 - 卡片组成的最大数字(Python) | 机试题算法思路 华为OD机试 - 网上商城优惠活动(一)(Python) | 机试题算法思路 华为OD机试 - 统计匹配的二元组个数(Python) | 机试题算法思路 华为OD机试 - 找到它(Python) | 机试题算法思路 华为OD机试…...
「6」线性代数(期末复习)
🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀 目录 第五章 相似矩阵及二次型 &2)方阵的特征值与特征向量 &3ÿ…...
1.1 硬件与micropython固件烧录及自编译固件
1.ESP32硬件和固件 淘宝搜ESP32模块,20-50元都有,自带usb口,即插即用. 固件下载地址:MicroPython - Python for microcontrollers 2.烧录方法 为简化入门难度,建议此处先使用带GUI的开发工具THonny,记得不是给你理发的tony老师. 烧录的入口是: 后期通过脚本一次型生成和烧…...
【MySQL进阶】视图 存储过程 触发器
😊😊作者简介😊😊 : 大家好,我是南瓜籽,一个在校大二学生,我将会持续分享Java相关知识。 🎉🎉个人主页🎉🎉 : 南瓜籽的主页…...
[Linux篇] Linux常见命令和权限
文章目录使用XShell登录Linux1.Linux常用基本命令:1.1 ls(列出当前的目录下都有哪些文件和目录)1.2 cd (change directory 切换目录)1.3 pwd(查看当前目录的绝对路径)1.4 touch(创建文件)1.5 ca…...
29岁从事功能测试被辞,面试2个月都找不到工作吗?
最近一个28岁老同学联系我,因为被公司辞退,找我倾诉,于是写下此文。 他是14年二本毕业,在我的印象里人特别懒,不爱学习,专业不好,毕业前因为都没找到合适工作,直接去创业了…...
【C#个人错题笔记1】
观前提醒 记录一些我不会或者少见的内容,不一定适合所有人 字符串拼接 int a3,b8; Console.WriteLine(ab);//11 Console.WriteLine("ab");//ab Console.WriteLine(a""b);//38 Console.WriteLine("ab"ab);//ab38 Console.WriteLine…...
基于lambda的mongodb查询插件
需求背景需要一个像mybatis plus 一样的基于lambda, 且面向对象的查询mongo数据的插件。在网上找了很久,没有发现有类似功能的插件。于是自己手写了一个,借助mongoTemplate屏蔽了底层查询语句的实现细节。在此基础上,实现了查询的统一封装。技…...
基于微信小程序的微信社团小程序
文末联系获取源码 开发语言:Java 框架:ssm JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7/8.0 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven3.3.9 浏览器…...
GEE学习笔记 七十三:【GEE之Python版教程七】静态展示影像和动态展示影像
我们使用GEE在线编辑可以直接通过在线的网页可以加载展示我们计算的结果,而python版的GEE要展示我们的计算结果可能就比较麻烦。如果有同学看过GEE的python版API中可以找到一个类ee.mapclient,这个类的介绍是它是GEE官方通过Tk写的一个加载展示地图的类。…...
PGLBox全面解决图训练速度、成本、稳定性、复杂算法四大问题!
图神经网络(Graph Neural Network,GNN)是近年来出现的一种利用深度学习直接对图结构数据进行学习的方法,通过在图中的节点和边上制定聚合的策略,GNN能够学习到图结构数据中节点以及边内在规律和更加深层次的语义特征。…...
超详细的 pytest 教程(一)使用入门篇
前言 pytest到目前为止还没有翻译的比较好全面的使用文档,很多英文不太好的小伙伴,在学习时看英文文档还是很吃力。本来去年就计划写pytest详细的使用文档的,由于时间关系一直搁置,直到今天才开始写。本文是第一篇,主…...
二叉树理论基础知识点
二叉树的种类 在我们解题过程中二叉树有两种主要的形式:满二叉树和完全二叉树 满二叉树 满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。 如图所示: 这…...
【算法基础】堆⭐⭐⭐
一、堆 1. 堆的概念 堆(heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质: (1)堆中某个结点的值总是不大于或不小于其父结点的值; (2)堆总是一棵完全二叉树。 将根结点最大的堆叫做最大堆或大根堆,根结点…...
时序预测 | MATLAB实现CNN-SVM卷积支持向量机时间序列预测
时序预测 | MATLAB实现CNN-SVM卷积支持向量机时间序列预测 目录时序预测 | MATLAB实现CNN-SVM卷积支持向量机时间序列预测预测效果基本介绍研究回顾程序设计参考资料预测效果 基本介绍 CNN-SVM预测模型将深度学习模型作为特征学习器,将SVM 支持向量机 作为训练器进行…...
【TypeScrip】TypeScrip的任意类型(Any 类型 和 unknown 顶级类型):
文章目录一、安转依赖:【1】nodejs 环境执行ts【2】使用ts-node二、Any 类型 和 unknown 顶级类型【1】没有强制限定哪种类型,随时切换类型都可以 我们可以对 any 进行任何操作,不需要检查类型【2】声明变量的时候没有指定任意类型默认为any【…...
智能洗地机什么牌子好?智能洗地机排行
要说家庭清洁热门的产品,洗地机肯定首当其冲,集洗吸拖为一体的清洁工具,省时又省力,可谓是家里清洁好助手,今天笔者就为大家介绍几款重量轻、噪音轻、拖地干净的洗地机! 一、CEYEE希亦T800洗地机 在国内,洗…...
【数据结构与算法】链表1:移除链表 设计链表链表反转(双指针法、递归法)
文章目录今日任务1.链表理论基础(1)什么是链表?(2)链表的类型(3)链表的存储方式(4)链表的定义(5)链表的操作(6)性能分析2.…...
山东大学软件学院面向对象简答题整理【个人向】
面向对象简答题整理【个人向】 0.试用面向对象语言简述改写和重定义的异同,以及方法绑定时的差别 改写是子类的方法和父类的方法具有相同的方法名和类型签名重定义是子类的方法和父类的方法方法名相同但类型签名不同在方法绑定时,改写是动态绑定&#…...
JAVA时间类及JAVA8新时间类
文章目录Java旧时间类关系图![在这里插入图片描述](https://img-blog.csdnimg.cn/e2c2c26c841e40bdb9cc85d0fc4bc1df.png)GMT、时间戳、统一标准时间、时区Java时间类创建时间类示例java.text.DateFormat时间格式转换java.util.Calendar总结Java时间类Java8新时间类InstantCloc…...
微商网络推广怎么做/seo站长工具综合查询
GET请求的参数在URL中,在原生Node中,需要使用url模块来识别参数字符串。在Express中,不需要使用url模块了。可以直接使用req.query对象。 ● POST请求在express中不能直接获得,必须使用body-parser模块。使用后,将可以…...
手机网站如何做营销/seo是什么化学名称
原创不易,转载请注明出处 文章目录前言1.使用demo2.lock原理3.unlock原理总结前言 redisson作为redis的客户端,提供了特别丰富的功能,关于redisson各种功能使用文档可以看下它的官网或者github,它还提供了基于redis各种分布式锁的…...
帮人网站开发维护违法/windows10优化软件
点击蓝色字免费订阅,每天收到这样的好信息一、数据治理与数据分类分级《DAMA 数据管理知识体系指南》给出的定义:数据治理是对数据资产管理行使权力和控制的活动集合(规划、监控和执行)。数据治理的职能是指导其他数据管理职能如何执行。数据治理就是以服…...
毕设web网站开发/p2p万能搜索种子
一、概念 IoC是Inversion of Control的缩写,有的翻译成“控制反转”,还有翻译为“控制反向”或者“控制倒置”。二、什么是IoC IoC就是IoC,不是什么技术,与GoF一样,是一种设计模式。在Spring中控制反转是Spring框架的核…...
天桥网站建设/网站优化公司收费
想删除某一路径之下所有文件: 删除文件,Insus.NET 写了2个方法,名称一样,重载而已。 原理简单,即是循环指定路径下所有目录和子目录来进行删除文件。重载的方法,带多一个参数。是想删除几天前的文件&#x…...
四川住房建设厅网站首页/官方百度下载安装
💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。⛳座右铭&#…...