当前位置: 首页 > 科技观察

用JavaScript编写更好的条件语句

时间:2023-03-21 23:56:43 科技观察

在任何编程语言中,代码都需要根据不同的条件对给定的输入做出不同的决定并执行相应的操作。例如,在游戏中,如果玩家命中0,则游戏结束。在天气应用程序中,如果在早上查看,会显示日出图像,如果是晚上,则会显示星星和月亮。在本文中,我们将探讨JavaScript中所谓的条件语句的工作原理。如果您使用JavaScript,您将编写大量包含条件调用的代码。条件调用一开始可能很容易学习,但它比编写成对的if/else要复杂得多。这里有一些有助于编写更好、更清晰的条件代码的技巧。1.数组方法Array.includes使用Array.includes进行多条件选择例如:functionprintAnimals(animal){if(animal==='dog'||animal==='cat'){console.log(Ihavea${动物});}}console.log(printAnimals('dog'));//Ihaveadog上面的代码看起来不错,因为我们只检查了两只动物。但是,我们不确定用户输入。如果我们要检查任何其他动物怎么办?如果我们通过添加更多的“或”语句来扩展,代码将变得难以维护和不清晰。解决方案:我们可以通过Array.includes;if(animals.includes(animal)){console.log(Ihavea${animal});}}console.log(printAnimals('hamster'));//Ihaveahamster在这里,我们创建了一个动物数组,因此可以从其余代码中抽象出条件语句。现在,如果我们想检查任何其他动物,我们只需要添加一个新的数组项。我们还可以在函数范围之外使用动物数组变量,以便在代码的其他任何地方重用它。这是一种编写更清晰、易于理解和可维护的代码的方法,不是吗?2.提前退出/提前返回这是一个非常棒的精简代码的技巧。我记得当我开始专业工作时,我在第一天就学会了使用提前退出来编写条件。让我们在前面的示例中添加更多条件。用包含已定义属性的对象替换简单字符串的动物。目前的需求是:如果没有动物,则抛出异常printtheanimaltypeprinttheanimalnameprinttheanimalgenderconstprintAnimalDetails=animal=>{letresult;//declareavariabletostorethefinalvalue//condition1:checkifanimalhasavalueif(animal){//condition2:checkifanimalhasatypepropertyif(animal.type){//condition3:checkifanimalhasanamepropertyif(animal.name){//condition4:checkifanimalhasagenderpropertyif(animal.gender){result=${animal.name}isa${animal.gender}${animal.type};;}else{result="Noanimalgender";}}else{result="Noanimalname";}}else{result="Noanimaltype";}}else{result="Noanimal";}returnresult;};console.log(printAnimalDetails());//'Noanimal'console.log(printAnimalDetails({type:"dog",gender:"female"}));//'Noanimalname'console.log(printAnimalDetails({type:"dog",name:"Lucy"}));//'Noanimalgender'console.log(printAnimalDetails({type:"dog",name:"Lucy",gender:"female"})));//'Lucyisafemaledog'你觉得上面的代码怎么样?它工作得很好,但代码很长且难以维护。如果您不使用lint工具,弄清楚右花括号的位置是浪费时间。:smile:想象一下如果代码有更复杂的逻辑?很多if..else语句。我们可以使用三元运算符、&&条件等语法重构上述功能,但让我们使用多个return语句编写更清晰的代码。constprintAnimalDetails=({type,name,gender}={})=>{if(!type)return'Noanimaltype';if(!name)return'Noanimalname';if(!gender)return'Noanimalgender';//现在这行代码,we'resurethatwehaveananimalwithall//threepropertieshere.return${name}isa${gender}${type};}console.log(printAnimalDetails());//'Noanimaltype'console.log(printAnimalDetails({type:dog}));//'Noanimalname'console.log(printAnimalDetails({type:dog,gender:female}));//'Noanimalname'console.log(printAnimalDetails({type:dog,name:'Lucy',gender:'female'}));//本次重构版本中的'Lucyisafemaledog'还包括解构和默认参数。默认参数确保如果我们将undefined作为方法参数传递,我们仍然有要解构的值,在这种情况下它是一个空对象{}。通常,在专业领域,代码是在这两种方法之间编写的。另一个例子:functionprintVegetablesWithQuantity(vegetable,quantity){constvegetables=['potato','cabbage','cauliflower','asparagus'];//condition1:vegetableshouldbepresentif(vegetable){//condition2:mustbeoneoftheitemfromthelistif(vegetables.includes(vegetable)){console.log(Ilike${vegetable});//condition3:mustbelargequantityif(quantity>=10){console.log('Ihaveboughtalargequantity');}}}else{thrownewError('Novegetablefromthelist!');}}printVegetablesWithQuantity(null);//Novegetablefromthelist!printVegetablesWithQuantity('cabbage');//IlikecabbageprintVegetablesWithQuantity('cabbage',20);//'Ilikecabbage//'Ihaveboughtallargequantity'现在,我们有:1if/else语句来过滤非法条件3级嵌套if语句(条件1、2和3)通常遵循的规则是:当匹配到非法条件时提前退出。functionprintVegetablesWithQuantity(vegetable,quantity){constvegetables=['potato','cabbage','cauliflower','asparagus'];//condition1:throwerrorearlyif(!vegetable)thrownewError('Novegetablefromthelist!');//condition2:mustbeinthelistif(vegetables.includes(vegetable)){console.log(Ilike${vegetable});//condition3:mustbeallargequantityif(quantity>=10){console.log('Ihaveboughtallargequantity');}}}通过这样做,我们有更少嵌套级别。当您有一个很长的if语句时,这种编码风格特别有效。我们可以通过反转条件和提前返回来进一步减少嵌套的if语句。看看下面的条件2,看看我们是如何做到的;//condition1:throwerrorearlyif(!vegetables.includes(vegetable))return;//condition2:returnfromthefunctionisthevegetableisnotin//thelistconsole.log(Ilike${vegetable});//condition3:mustbeallargequantityif(quantity>=10){console.log('Ihaveboughtallargequantity');}}通过反转条件2,代码没有嵌套语句。当我们有很多条件并且我们希望在任何特定条件不匹配时停止进一步处理时,此技术特别有用。因此,始终关注减少嵌套和提前回报,但也不要过度。3.用对象字面量或Map替换Switch语句我们看下面的例子,我们要根据颜色打印水果:','草莓'];case'黄色':return['banana','pineapple'];case'purple':return['grape','plum'];default:return[];}}printFruits(null);//[]printFruits('yellow');//['banana','pineapple']上面的代码是正确的,但是还是有点冗长。使用具有更清晰语法的对象文字可以实现相同的功能://useobjectliteraltofindfruitsbycolorconstfruitColor={red:['apple','strawberry'],yellow:['banana','pineapple'],purple:['grape','plum']};functionprintFruits(color){returnfruitColor[color]||[];}另外,还可以使用Map实现同样的功能://useMaptofindfruitsbycolorconstfruitColor=newMap().set('red',['apple','strawberry']).set('yellow',['banana','pineapple']).set('purple',['grape','plum']);functionprintFruits(color){returnfruitColor.get(color)||[];}Map允许存储键值对,是ES2015之后可用的对象类型。对于上面的例子,同样的功能也可以用数组方法Array.filter来实现。constfruits=[{name:'apple',color:'red'},{name:'strawberry',color:'red'},{name:'banana',color:'yellow'},{name:'菠萝',color:'yellow'},{name:'grape',color:'purple'},{name:'plum',color:'purple'}];functionprintFruits(color){returnfruits.filter(fruit=>fruit.color===color);}4.默认参数和解构在使用JavaScript时,我们总是需要检查null/undefined值并分配默认值,否则编译可能会失败。functionprintVegetablesWithQuantity(vegetable,quantity=1){//ifquantity没有值,assign1if(!vegetable)return;console.log(Wehave${quantity}${vegetable}!);}//resultsprintVegetablesWithQuantity('cabbage');//Wehave1cabbage!printVegetablesWithQuantity('potato',2);//我们有2个土豆!如果蔬菜是一个对象呢?我们可以分配一个默认参数吗?functionprintVegetableName(vegetable){if(vegetable&&vegetable.name){console.log(vegetable.name);}else{console.log('unknown');}}printVegetableName(undefined);//unknownprintVegetableName({});//unknownprintVegetableName({name:'cabbage',quantity:2});//cabbage在上面的例子中,如果蔬菜存在,我们要打印蔬菜名称,否则打印“unknown”。我们可以通过使用默认参数和解构来避免条件语句if(vegetable&&vegetable.name){}。//destructing-getnamepropertyonly//assigndefaultemptyobject{}functionprintVegetableName({name}={}){console.log(name||'unknown');}printVegetableName(undefined);//unknownprintVegetableName({});//unknownprintVegetableName({name:'cabbage',quantity:2});//cabbage因为我们只需要name属性,所以我们可以使用{name}来解构参数,然后我们可以在代码中使用name作为变量,而不是vegetable。姓名。我们还分配了一个空对象{}作为默认值,因为在执行printVegetableName(undefined)时我们得到一个错误:Cannotdeconstructpropertynamefromundefinedornullbecausethereisnonamepropertyinundefined。5.使用Array.every&Array.some来匹配全部/部分内容我们可以使用数组方法来减少代码行数。查看下面的代码,我们要检查是否所有水果都是红色的:constfruits=[{name:'apple',color:'red'},{name:'banana',color:'yellow'},{name:'葡萄',color:'紫色'}];functiontest(){letisAllRed=true;//条件:allfruitsmustberedfor(letffruits){if(!isAllRed)break;isAllRed=(f.color=='red');}console.log(isAllRed);//false}这段代码太长了!我们可以使用Array.every来减少代码行数:constfruits=[{name:'apple',color:'red'},{name:'banana',color:'yellow'},{name:'grape',color:'purple'}];functiontest(){//condition:shortway,allfruitsmustberedconstisAllRed=fruits.every(f=>f.color=='red');console.log(isAllRed);//false}同样,如果我们想测试是否有红色水果,我们可以用一行Array.some来完成。constfruits=[{name:'apple',color:'red'},{name:'banana',color:'yellow'},{name:'grape',color:'purple'}];functiontest(){//condition:ifanyfruitisredconstisAnyRed=fruits.some(f=>f.color=='red');console.log(isAnyRed);//true}6.使用可选链和空值合并这有两个用于编写更清晰的条件语句是即将推出的JavaScript增强功能。在撰写本文时,它们还没有得到完全支持,您需要使用Babel来编译它们。可选链接允许我们处理树状结构而无需显式检查中间节点的存在。空合并和可选链接可以很好地结合使用,以确保为不存在的值分配默认值。下面是一个例子:constcar={model:'Fiesta',manufacturer:{name:'Ford',address:{street:'SomeStreetName',number:'5555',state:'USA'}}}//togetthecarmodelconstmodel=car&&car.model||'defaultmodel';//获取manufacturerstreetconststreet=car&&car.manufacturer&&car.manufacturer.address&&car.manufacturer.address.street||'defaultstreet';//请求不存在的属性constphoneNumber=car&&car.manufacturer&&car.manufacturer.address&&car.manunumber;urer.phone.console.log(model)//'Fiesta'console.log(street)//'SomeStreetName'console.log(phoneNumber)//undefined所以,如果我们想打印汽车制造商是否来自美国,代码将看起来像这样:constisManufacturerFromUSA=()=>{if(car&&car.manufacturer&&car.manufacturer.address&&car.manufacturer.address.state==='USA'){console.log('true');}}checkCarManufacturerState()//'true'当你有一个更复杂的对象结构时,你可以清楚地看到这会变得多么混乱。有第三方库有自己的功能,比如lodash或idx。例如lodash有一个_.get方法。但是,将JavaScript语言本身引入此功能真是太酷了。这显示了这些新功能是如何工作的://togetthecarmodelconstmodel=car?.model??'defaultmodel';//togetthemanufacturersstreetconststreet=car?.manufacturer?.address?.street??'defaultstreet';//tocheckifthecarmanufacturerisfromtheUSAconstisManufacturerFromUSA=()=>{if(car?.manufacturer?.address?.state==='USA'){console.log('true');}}这看起来不错并且易于维护。现在是TC39第3阶段,让我们等待它获得批准,然后我们才能看到这种令人难以置信的语法无处不在。总结让我们学习和尝试新的技巧和技术,以便编写更清晰、更易于维护的代码,因为几个月后,长期的情况看起来就像搬起石头砸自己的脚。