使用 JavaScript 編寫更好的條件語句


 做者:cuppar
https://www.zcfy.cc/article/tips-to-write-better-conditionals-in-javascript-dev-community

在任何編程語言中,代碼須要根據不一樣的條件在給定的輸入中作不一樣的決定和執行相應的動做。javascript

例如,在一個遊戲中,若是玩家生命點爲0,遊戲結束。在天氣應用中,若是在早上被查看,顯示一個日出圖片,若是是晚上,則顯示星星和月亮。在這篇文章中,咱們將探索JavaScript中所謂的條件語句如何工做。vue

若是你使用JavaScript工做,你將寫不少包含條件調用的代碼。條件調用可能初學很簡單,可是還有比寫一對對if/else更多的東西。這裏有些編寫更好更清晰的條件代碼的有用提示。java

  1. 數組方法 Array.includes
  2. 提早退出 / 提早返回
  3. 用對象字面量或Map替代Switch語句
  4. 默認參數和解構
  5. 用 Array.every & Array.some 匹配所有/部份內容
  6. 使用可選鏈和空值合併

1. 數組方法 Array.includes

使用 Array.includes 進行多條件選擇web

例如:編程

function printAnimals(animal{
    if (animal === 'dog' || animal === 'cat') {
        console.log(I have a ${animal});
    }
}

console.log(printAnimals('dog')); // I have a dog

上面的代碼看起來很好由於咱們只檢查了兩個動物。然而,咱們不肯定用戶輸入。若是咱們要檢查任何其餘動物呢?若是咱們經過添加更多「或」語句來擴展,代碼將變得難以維護和不清晰。數組

解決方案:微信

咱們能夠經過使用 Array.includes 來重寫上面的條件app

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

這裏,咱們建立來一個動物數組,因此條件語句能夠和代碼的其他部分抽象分離出來。如今,若是咱們想要檢查任何其餘動物,咱們只須要添加一個新的數組項。編程語言

咱們也能在這個函數做用域外部使用這個動物數組變量來在代碼中的其餘任意地方重用它。這是一個編寫更清晰、易理解和維護的代碼的方法,不是嗎?編輯器

2. 提早退出 / 提早返回

這是一個精簡你的代碼的很是酷的技巧。我記得當我開始專業工做時,我在第一天學習使用提早退出來編寫條件。

讓咱們在以前的例子上添加更多的條件。用包含肯定屬性的對象替代簡單字符串的動物。

如今的需求是:

  • 若是沒有動物,拋出一個異常
  • 打印動物類型
  • 打印動物名字
  • 打印動物性別
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'

你以爲上面的代碼怎麼樣?

它工做得很好,可是代碼很長而且維護困難。若是不使用lint工具,找出閉合花括號在哪都會浪費不少時間。😄 想象若是代碼有更復雜的邏輯會怎麼樣?大量的if..else語句。

咱們能用三元運算符、&&條件等語法重構上面的功能,但讓咱們用多個返回語句編寫更清晰的代碼。

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'

在這個重構過的版本中,也包含了解構和默認參數。默認參數確保若是咱們傳遞undefined做爲一個方法的參數,咱們仍然有值能夠解構,在這裏它是一個空對象{}。

一般,在專業領域,代碼被寫在這兩種方法之間。

另外一個例子:

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'

如今,咱們有:

  • 1 if/else 語句過濾非法條件
  • 3 級嵌套if語句 (條件 1, 2, & 3)

一個廣泛遵循的規則是:在非法條件匹配時提早退出。

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');
      }
   }
}

經過這麼作,咱們少了一個嵌套層級。當你有一個長的if語句時,這種代碼風格特別好。

咱們能經過條件倒置和提早返回,進一步減小嵌套的if語句。查看下面的條件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');
  }
}

經過倒置條件2,代碼沒有嵌套語句了。這種技術在咱們有不少條件而且當任何特定條件不匹配時,咱們想中止進一步處理的時候特別有用。

因此,老是關注更少的嵌套和提早返回,但也不要過分地使用。

3. 用對象字面量或Map替代Switch語句

讓咱們來看看下面的例子,咱們想要基於顏色打印水果:

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']

上面的代碼沒有錯誤,可是它仍然有些冗長。相同的功能能用對象字面量以更清晰的語法實現:

// 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 來實現相同的功能:

// 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 容許保存鍵值對,是自從ES2015以來可使用的對象類型。

對於上面的例子,相同的功能也能用數組方法Array.filter 來實現。

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. 默認參數和解構

當使用 JavaScript 工做時,咱們老是須要檢查 null/undefined 值並賦默認值,不然可能編譯失敗。

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 是一個對象呢?咱們能賦一個默認參數嗎?

function printVegetableName(vegetable
    if (vegetable && vegetable.name) {
     console.log (vegetable.name);
   } else {
    console.log('unknown');
   }
}

printVegetableName(undefined); // unknown
printVegetableName({}); // unknown
printVegetableName({ name'cabbage'quantity2 }); // cabbage

在上面的例子中,若是vegetable 存在,咱們想要打印 vegetable name, 不然打印"unknown"。

咱們能經過使用默認參數和解構來避免條件語句 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'quantity2 }); // cabbage

由於咱們只須要 name 屬性,因此咱們可使用 { name } 解構參數,而後咱們就能在代碼中使用 name 做爲變量,而不是 vegetable.name

咱們還賦了一個空對象 {} 做爲默認值,由於當執行 printVegetableName(undefined) 時會獲得一個錯誤:不能從 undefinednull 解構屬性 name ,由於在 undefined 中沒有 name 屬性。

5. 用 Array.every & Array.some 匹配所有/部份內容

咱們能使用數組方法減小代碼行。查看下面的代碼,咱們想要檢查是否全部的水果都是紅色的:

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
}

這代碼太長了!咱們能用 Array.every 來減小代碼行數:

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
}

類似地,若是咱們想測試是否有任何紅色的水果,咱們能用一行 Array.some 來實現它。

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. 使用可選鏈和空值合併

這有兩個爲編寫更清晰的條件語句而即將成爲 JavaScript 加強的功能。當寫這篇文章時,它們尚未被徹底支持,你須要使用 Babel 來編譯。

可選鏈容許咱們沒有明確檢查中間節點是否存在地處理 tree-like 結構,空值合併和可選鏈組合起來工做得很好,以確保爲不存在的值賦一個默認值。

這有一個例子:

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

因此,若是咱們想要打印是否車輛生產商來自美國,代碼將看起來像這樣:

const isManufacturerFromUSA = () => {
   if(car && car.manufacturer && car.manufacturer.address && 
 car.manufacturer.address.state === 'USA') {
     console.log('true');
   }
}


checkCarManufacturerState() // 'true'

你能清晰地看到當有一個更復雜的對象結構時,這能變得多亂。有一些第三方的庫有它們本身的函數,像 lodash 或 idx。例如 lodash 有 _.get 方法。然而,JavaScript 語言自己被引入這個特性是很是酷的。

這展現了這些新特性如何工做:

// 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');
   }
}

這看起來很美觀並容易維護。它已經到 TC39 stage 3 階段,讓咱們等待它得到批准,而後咱們就能無處不在地看到這難以置信的語法的使用。

總結

讓咱們爲了編寫更清晰、易維護的代碼,學習並嘗試新的技巧和技術,由於在幾個月後,長長的條件看起來像搬石頭砸本身的腳。😄


近期
Vue超好玩的新特性:在CSS中使用JS變量
完全理解 Cookie、Session、Token、JWT

若此文有用,何不素質三連❤️

本文分享自微信公衆號 - Vue中文社區(vue_fe)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索