如何利用JavaScript編寫更好的條件語(yǔ)句詳解
前言
在任何編程語(yǔ)言中,代碼需要根據(jù)不同的條件在給定的輸入中做不同的決定和執(zhí)行相應(yīng)的動(dòng)作。
例如,在一個(gè)游戲中,如果玩家生命點(diǎn)為0,游戲結(jié)束。在天氣應(yīng)用中,如果在早上被查看,顯示一個(gè)日出圖片,如果是晚上,則顯示星星和月亮。在這篇文章中,我們將探索JavaScript中所謂的條件語(yǔ)句如何工作。
如果你使用JavaScript工作,你將寫很多包含條件調(diào)用的代碼。條件調(diào)用可能初學(xué)很簡(jiǎn)單,但是還有比寫一對(duì)對(duì)if/else更多的東西。這里有些編寫更好更清晰的條件代碼的有用提示。
1. 數(shù)組方法 Array.includes
使用 Array.includes 進(jìn)行多條件選擇
例如:
function printAnimals(animal) { if (animal === 'dog' || animal === 'cat') { console.log(I have a ${animal}); } } console.log(printAnimals('dog')); // I have a dog
上面的代碼看起來(lái)很好因?yàn)槲覀冎粰z查了兩個(gè)動(dòng)物。然而,我們不確定用戶輸入。如果我們要檢查任何其他動(dòng)物呢?如果我們通過(guò)添加更多“或”語(yǔ)句來(lái)擴(kuò)展,代碼將變得難以維護(hù)和不清晰。
解決方案:
我們可以通過(guò)使用 Array.includes 來(lái)重寫上面的條件
function printAnimals(animal) { const animals = ['dog', 'cat', 'hamster', 'turtle']; if (animals.includes(animal)) { console.log(I have a ${animal}); } } console.log(printAnimals('hamster')); // I have a hamster
這里,我們創(chuàng)建來(lái)一個(gè)動(dòng)物數(shù)組,所以條件語(yǔ)句可以和代碼的其余部分抽象分離出來(lái)?,F(xiàn)在,如果我們想要檢查任何其他動(dòng)物,我們只需要添加一個(gè)新的數(shù)組項(xiàng)。
我們也能在這個(gè)函數(shù)作用域外部使用這個(gè)動(dòng)物數(shù)組變量來(lái)在代碼中的其他任意地方重用它。這是一個(gè)編寫更清晰、易理解和維護(hù)的代碼的方法,不是嗎?
2. 提前退出 / 提前返回
這是一個(gè)精簡(jiǎn)你的代碼的非??岬募记伞N矣浀卯?dāng)我開始專業(yè)工作時(shí),我在第一天學(xué)習(xí)使用提前退出來(lái)編寫條件。
讓我們?cè)谥暗睦由咸砑痈嗟臈l件。用包含確定屬性的對(duì)象替代簡(jiǎn)單字符串的動(dòng)物。
現(xiàn)在的需求是:
- 如果沒(méi)有動(dòng)物,拋出一個(gè)異常
- 打印動(dòng)物類型
- 打印動(dòng)物名字
- 打印動(dòng)物性別
const printAnimalDetails = animal => { let result; // declare a variable to store the final value // condition 1: check if animal has a value if (animal) { // condition 2: check if animal has a type property if (animal.type) { // condition 3: check if animal has a name property if (animal.name) { // condition 4: check if animal has a gender property if (animal.gender) { result = ${animal.name} is a ${animal.gender} ${animal.type};; } else { result = "No animal gender"; } } else { result = "No animal name"; } } else { result = "No animal type"; } } else { result = "No animal"; } return result; }; console.log(printAnimalDetails()); // 'No animal' console.log(printAnimalDetails({ type: "dog", gender: "female" })); // 'No animal name' console.log(printAnimalDetails({ type: "dog", name: "Lucy" })); // 'No animal gender' console.log( printAnimalDetails({ type: "dog", name: "Lucy", gender: "female" }) ); // 'Lucy is a female dog'
你覺(jué)得上面的代碼怎么樣?
它工作得很好,但是代碼很長(zhǎng)并且維護(hù)困難。如果不使用lint工具,找出閉合花括號(hào)在哪都會(huì)浪費(fèi)很多時(shí)間。 😄 想象如果代碼有更復(fù)雜的邏輯會(huì)怎么樣?大量的if..else語(yǔ)句。
我們能用三元運(yùn)算符、&&條件等語(yǔ)法重構(gòu)上面的功能,但讓我們用多個(gè)返回語(yǔ)句編寫更清晰的代碼。
const printAnimalDetails = ({type, name, gender } = {}) => { if(!type) return 'No animal type'; if(!name) return 'No animal name'; if(!gender) return 'No animal gender'; // Now in this line of code, we're sure that we have an animal with all //the three properties here. return ${name} is a ${gender} ${type}; } console.log(printAnimalDetails()); // 'No animal type' console.log(printAnimalDetails({ type: dog })); // 'No animal name' console.log(printAnimalDetails({ type: dog, gender: female })); // 'No animal name' console.log(printAnimalDetails({ type: dog, name: 'Lucy', gender: 'female' })); // 'Lucy is a female dog'
在這個(gè)重構(gòu)過(guò)的版本中,也包含了解構(gòu)和默認(rèn)參數(shù)。默認(rèn)參數(shù)確保如果我們傳遞undefined作為一個(gè)方法的參數(shù),我們?nèi)匀挥兄悼梢越鈽?gòu),在這里它是一個(gè)空對(duì)象{}。
通常,在專業(yè)領(lǐng)域,代碼被寫在這兩種方法之間。
另一個(gè)例子:
function printVegetablesWithQuantity(vegetable, quantity) { const vegetables = ['potato', 'cabbage', 'cauliflower', 'asparagus']; // condition 1: vegetable should be present if (vegetable) { // condition 2: must be one of the item from the list if (vegetables.includes(vegetable)) { console.log(I like ${vegetable}); // condition 3: must be large quantity if (quantity >= 10) { console.log('I have bought a large quantity'); } } } else { throw new Error('No vegetable from the list!'); } } printVegetablesWithQuantity(null); // No vegetable from the list! printVegetablesWithQuantity('cabbage'); // I like cabbage printVegetablesWithQuantity('cabbage', 20); // 'I like cabbage // 'I have bought a large quantity'
現(xiàn)在,我們有:
1 if/else 語(yǔ)句過(guò)濾非法條件
3 級(jí)嵌套if語(yǔ)句 (條件 1, 2, & 3)
一個(gè)普遍遵循的規(guī)則是:在非法條件匹配時(shí)提前退出。
function printVegetablesWithQuantity(vegetable, quantity) { const vegetables = ['potato', 'cabbage', 'cauliflower', 'asparagus']; // condition 1: throw error early if (!vegetable) throw new Error('No vegetable from the list!'); // condition 2: must be in the list if (vegetables.includes(vegetable)) { console.log(I like ${vegetable}); // condition 3: must be a large quantity if (quantity >= 10) { console.log('I have bought a large quantity'); } } }
通過(guò)這么做,我們少了一個(gè)嵌套層級(jí)。當(dāng)你有一個(gè)長(zhǎng)的if語(yǔ)句時(shí),這種代碼風(fēng)格特別好。
我們能通過(guò)條件倒置和提前返回,進(jìn)一步減少嵌套的if語(yǔ)句。查看下面的條件2,觀察我們是怎么做的:
function printVegetablesWithQuantity(vegetable, quantity) { const vegetables = ['potato', 'cabbage', 'cauliflower', 'asparagus']; if (!vegetable) throw new Error('No vegetable from the list!'); // condition 1: throw error early if (!vegetables.includes(vegetable)) return; // condition 2: return from the function is the vegetable is not in // the list console.log(I like ${vegetable}); // condition 3: must be a large quantity if (quantity >= 10) { console.log('I have bought a large quantity'); } }
通過(guò)倒置條件2,代碼沒(méi)有嵌套語(yǔ)句了。這種技術(shù)在我們有很多條件并且當(dāng)任何特定條件不匹配時(shí),我們想停止進(jìn)一步處理的時(shí)候特別有用。
所以,總是關(guān)注更少的嵌套和提前返回,但也不要過(guò)度地使用。
3. 用對(duì)象字面量或Map替代Switch語(yǔ)句
讓我們來(lái)看看下面的例子,我們想要基于顏色打印水果:
function printFruits(color) { // use switch case to find fruits by color switch (color) { case 'red': return ['apple', 'strawberry']; case 'yellow': return ['banana', 'pineapple']; case 'purple': return ['grape', 'plum']; default: return []; } } printFruits(null); // [] printFruits('yellow'); // ['banana', 'pineapple']
上面的代碼沒(méi)有錯(cuò)誤,但是它仍然有些冗長(zhǎng)。相同的功能能用對(duì)象字面量以更清晰的語(yǔ)法實(shí)現(xiàn):
// use object literal to find fruits by color const fruitColor = { red: ['apple', 'strawberry'], yellow: ['banana', 'pineapple'], purple: ['grape', 'plum'] }; function printFruits(color) { return fruitColor[color] || []; }
另外,你也能用Map來(lái)實(shí)現(xiàn)相同的功能:
// use Map to find fruits by color const fruitColor = new Map() .set('red', ['apple', 'strawberry']) .set('yellow', ['banana', 'pineapple']) .set('purple', ['grape', 'plum']); function printFruits(color) { return fruitColor.get(color) || []; }
Map 允許保存鍵值對(duì),是自從ES2015以來(lái)可以使用的對(duì)象類型。
對(duì)于上面的例子,相同的功能也能用數(shù)組方法 Array.filte 來(lái)實(shí)現(xiàn)。
const fruits = [ { name: 'apple', color: 'red' }, { name: 'strawberry', color: 'red' }, { name: 'banana', color: 'yellow' }, { name: 'pineapple', color: 'yellow' }, { name: 'grape', color: 'purple' }, { name: 'plum', color: 'purple' } ]; function printFruits(color) { return fruits.filter(fruit => fruit.color === color); }
4. 默認(rèn)參數(shù)和解構(gòu)
當(dāng)使用 JavaScript 工作時(shí),我們總是需要檢查 null/undefined 值并賦默認(rèn)值,否則可能編譯失敗。
function printVegetablesWithQuantity(vegetable, quantity = 1) { // if quantity has no value, assign 1 if (!vegetable) return; console.log(We have ${quantity} ${vegetable}!); } //results printVegetablesWithQuantity('cabbage'); // We have 1 cabbage! printVegetablesWithQuantity('potato', 2); // We have 2 potato!
如果 vegetable 是一個(gè)對(duì)象呢?我們能賦一個(gè)默認(rèn)參數(shù)嗎?
function printVegetableName(vegetable) { if (vegetable && vegetable.name) { console.log (vegetable.name); } else { console.log('unknown'); } } printVegetableName(undefined); // unknown printVegetableName({}); // unknown printVegetableName({ name: 'cabbage', quantity: 2 }); // cabbage
在上面的例子中,如果vegetable 存在,我們想要打印 vegetable name, 否則打印"unknown"。
我們能通過(guò)使用默認(rèn)參數(shù)和解構(gòu)來(lái)避免條件語(yǔ)句 if (vegetable && vegetable.name) {} 。
// destructing - get name property only // assign default empty object {} function printVegetableName({name} = {}) { console.log (name || 'unknown'); } printVegetableName(undefined); // unknown printVegetableName({ }); // unknown printVegetableName({ name: 'cabbage', quantity: 2 }); // cabbage
因?yàn)槲覀冎恍枰?name 屬性,所以我們可以使用 { name } 解構(gòu)參數(shù),然后我們就能在代碼中使用 name 作為變量,而不是 vegetable.name。
我們還賦了一個(gè)空對(duì)象 {} 作為默認(rèn)值,因?yàn)楫?dāng)執(zhí)行 printVegetableName(undefined) 時(shí)會(huì)得到一個(gè)錯(cuò)誤:不能從 undefined 或 null 解構(gòu)屬性 name,因?yàn)樵?undefined 中沒(méi)有name屬性。
5. 用 Array.every & Array.some 匹配全部/部分內(nèi)容
我們能使用數(shù)組方法減少代碼行。查看下面的代碼,我們想要檢查是否所有的水果都是紅色的:
const fruits = [ { name: 'apple', color: 'red' }, { name: 'banana', color: 'yellow' }, { name: 'grape', color: 'purple' } ]; function test() { let isAllRed = true; // condition: all fruits must be red for (let f of fruits) { if (!isAllRed) break; isAllRed = (f.color == 'red'); } console.log(isAllRed); // false }
這代碼太長(zhǎng)了!我們能用 Array.every 來(lái)減少代碼行數(shù):
const fruits = [ { name: 'apple', color: 'red' }, { name: 'banana', color: 'yellow' }, { name: 'grape', color: 'purple' } ]; function test() { // condition: short way, all fruits must be red const isAllRed = fruits.every(f => f.color == 'red'); console.log(isAllRed); // false }
相似地,如果我們想測(cè)試是否有任何紅色的水果,我們能用一行 Array.some 來(lái)實(shí)現(xiàn)它。
const fruits = [ { name: 'apple', color: 'red' }, { name: 'banana', color: 'yellow' }, { name: 'grape', color: 'purple' } ]; function test() { // condition: if any fruit is red const isAnyRed = fruits.some(f => f.color == 'red'); console.log(isAnyRed); // true }
6. 使用可選鏈和空值合并
這有兩個(gè)為編寫更清晰的條件語(yǔ)句而即將成為 JavaScript 增強(qiáng)的功能。當(dāng)寫這篇文章時(shí),它們還沒(méi)有被完全支持,你需要使用 Babel 來(lái)編譯。
可選鏈允許我們沒(méi)有明確檢查中間節(jié)點(diǎn)是否存在地處理 tree-like 結(jié)構(gòu),空值合并和可選鏈組合起來(lái)工作得很好,以確保為不存在的值賦一個(gè)默認(rèn)值。
這有一個(gè)例子:
const car = { model: 'Fiesta', manufacturer: { name: 'Ford', address: { street: 'Some Street Name', number: '5555', state: 'USA' } } } // to get the car model const model = car && car.model || 'default model'; // to get the manufacturer street const street = car && car.manufacturer && car.manufacturer.address && car.manufacturer.address.street || 'default street'; // request an un-existing property const phoneNumber = car && car.manufacturer && car.manufacturer.address && car.manufacturer.phoneNumber; console.log(model) // 'Fiesta' console.log(street) // 'Some Street Name' console.log(phoneNumber) // undefined
所以,如果我們想要打印是否車輛生產(chǎn)商來(lái)自美國(guó),代碼將看起來(lái)像這樣:
const isManufacturerFromUSA = () => { if(car && car.manufacturer && car.manufacturer.address && car.manufacturer.address.state === 'USA') { console.log('true'); } } checkCarManufacturerState() // 'true'
你能清晰地看到當(dāng)有一個(gè)更復(fù)雜的對(duì)象結(jié)構(gòu)時(shí),這能變得多亂。有一些第三方的庫(kù)有它們自己的函數(shù),像 lodash 或 idx。例如 lodash 有 _.get 方法。然而,JavaScript 語(yǔ)言本身被引入這個(gè)特性是非常酷的。
這展示了這些新特性如何工作:
// to get the car model const model = car?.model ?? 'default model'; // to get the manufacturer street const street = car?.manufacturer?.address?.street ?? 'default street'; // to check if the car manufacturer is from the USA const isManufacturerFromUSA = () => { if(car?.manufacturer?.address?.state === 'USA') { console.log('true'); } }
這看起來(lái)很美觀并容易維護(hù)。它已經(jīng)到 TC39 stage 3 階段,讓我們等待它獲得批準(zhǔn),然后我們就能無(wú)處不在地看到這難以置信的語(yǔ)法的使用。
總結(jié)
讓我們?yōu)榱司帉懜逦?、易維護(hù)的代碼,學(xué)習(xí)并嘗試新的技巧和技術(shù),因?yàn)樵趲讉€(gè)月后,長(zhǎng)長(zhǎng)的條件看起來(lái)像搬石頭砸自己的腳。 😄
到此這篇關(guān)于如何利用JavaScript編寫更好的條件語(yǔ)句的文章就介紹到這了,更多相關(guān)JavaScript條件語(yǔ)句內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
原生javascript+css3編寫的3D魔方動(dòng)畫旋扭特效
這篇文章主要介紹了原生javascript+css3編寫的3D魔方動(dòng)畫旋扭特效的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-03-03JavaScript 嚴(yán)格模式(use strict)用法實(shí)例分析
這篇文章主要介紹了JavaScript 嚴(yán)格模式(use strict)用法,結(jié)合實(shí)例形式分析了JavaScript 嚴(yán)格模式的基本功能、用法及操作注意事項(xiàng),需要的朋友可以參考下2020-03-03setTimeout的延時(shí)為0時(shí)多個(gè)瀏覽器的區(qū)別
一直比較迷惑:js的setTimeout到底會(huì)在什么時(shí)候執(zhí)行,如果執(zhí)行了,和主執(zhí)行腳本到底差多長(zhǎng)時(shí)間2012-05-05JS實(shí)現(xiàn)左右拖動(dòng)改變內(nèi)容顯示區(qū)域大小的方法
這篇文章主要介紹了JS實(shí)現(xiàn)左右拖動(dòng)改變內(nèi)容顯示區(qū)域大小的方法,涉及JavaScript實(shí)時(shí)響應(yīng)鼠標(biāo)事件動(dòng)態(tài)改變頁(yè)面元素屬性的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10Makefile/cmake/node-gyp中區(qū)分判斷不同平臺(tái)的方法
今天小編就為大家分享一篇關(guān)于Makefile/cmake/node-gyp中區(qū)分判斷不同平臺(tái)的方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12父節(jié)點(diǎn)獲取子節(jié)點(diǎn)的字符串示例代碼
這篇文章主要介紹了父節(jié)點(diǎn)獲取子節(jié)點(diǎn)的字符串的方法,需要的朋友可以參考下2014-02-02