提升代碼幸福度,五個技巧減少js開發中的if else語句


 壹 ❀ 引

在JavaScript開發中,條件判斷語句的使用頻率是極高的,而對於條件判斷簡單易讀的if else應該都是大家的首選。可是代碼寫的久了,我們總是希望自己的代碼看着能更為簡潔規范(逼格更高),那么今天我們就由淺到深介紹幾種實用小技巧,幫大家減少代碼中的if else。說在開頭,本文並未有消滅或歧視 if else的意思,if else的好用都知道,這里只是在某些特定場景為大家額外提供一種思路罷了,如何使用還請自行抉擇,那么本文開始。

 貳 ❀ 短路求值

在函數定義時,常有若函數調用未提供參數則使用默認值的情景,當然我們可以使用if else來解決這個問題:

function fn(name) {
    if(!name){
        name = '聽風是風';
    };
    console.log(name);
};
fn();//聽風是風
fn('行星飛行');//行星飛行

有沒有更優雅的做法呢?當然,我們可以使用短路求值,像這樣:

function fn(name) {
    name = name || '聽風是風';
    console.log(name);
};
fn();//聽風是風
fn('行星飛行');//行星飛行

我們簡單復習下 ||或 和 &&與 的概念,||表示兩者任意一個為真便為真,&&表示兩者都為真才是真,任意一個為假就是假。

為什么這個特定能用在變量賦值呢?其實這是利用了 || 前者為真后者不判斷,&&前者為假后者不判斷的特點,來看個例子:

function fn() {
    console.log(1);
};
true || fn(); //不執行
false && fn(); //不執行
false || fn(); //1
true && fn() //1

所以上面的短路求值中,當name有值時后面的默認值就被忽略了不判斷,而name無值時便會判斷后者取到默認值。

短路求值除了用在變量賦值外,還能用於函數調用,比如在下方例子為假時才調用某個方法:

let name = false;
function fn() {
    console.log(1);
};
//if
if (!name) {
    fn();//1
};
//短路
!name && fn();//1

 對於函數形參短路賦值其實有個缺點,假設我的參數就是0,false或者null,因為短路的特性會被認為假,這樣我們無法拿到想要的值,更佳的做法是使用ES6的形參默認值,像這樣:

function fn(param) {
    param = param || 1;
    console.log(param);
};
fn(0); //1
fn(null); //1
fn(false); //1

//使用形參默認值
function fn1(param = 1) {
    console.log(param);
};
fn1(); //1
fn1(0); //0
fn1(null); //null
fn1(false); //false

 叄 ❀ 三元運算符

三元運算符我想大家都不會陌生,在開發中三元運算的使用場景其實非常多,比如我希望為條件為 true時變量為1,反之為0,通過三元運算符我們可以這樣做:

let blo = true;
let num;
if (blo) {
    num = 1;
} else {
    num = 0;
};
console.log(num);//1

//三元運算符
blo =false;
blo ? num = 1 : num = 0;
console.log(num);//0

比如我們希望條件為true時調用函數fn,為false時什么也不做,使用三元看起來也會更加舒服:

let blo = true;
let fn = function () {
    console.log(1);
};
//if
if (blo) {
    fn(); //1
};

//三元
blo ? fn() : null;//1

在開發中函數常常需要 return 一份數據回去,有時候根據條件不同我們可能要分別對應返回不同的數據,三元也能解決這個問題:

let fn = function () {
    let flo = true;
    if (flo) {
        return 1;
    } else {
        return 2;
    };
};
let f = fn(); //1

let fn1 = function () {
    let flo = true;
    //三元
    return flo ? 1 : 2;
};
let f1 = fn1();//1

三元結合return的操作非常適合我們遞歸處理時做收尾工作,如果滿足條件繼續遞歸,不滿足跳出遞歸,比如我們要求正整數N到0之間所有整數之和,可以這么寫:

let result = 0;
function add(n){
    result += n
    return n>=2 ? add(n-1) : result;
};
let num = add(10);//55

怎么樣?看着是不是特別簡潔舒服。需要注意的是,三元運算符的表達式只能是單語句,否則無法使用,比如下方例子中由於執行語句超過了2句,這就無法使用三元運算符改寫了:

let i = 5;
if (i > 0) {
    //執行語句超過2句
    console.log(1);
    i = 0;
};

 肆 ❀ switch case

短路求值與三元運算符固然好用,但其實有一個遺憾,它們都只能解決非A即B的條件判斷,凡是條件判斷超過兩種就顯得十分無力了。那難道我們只能使用 else if 嗎,其實可以使用switch case。

例如A情況我們希望A情況輸出a,B情況輸出b,C情況輸出c,其它情況輸出d,用 else if 與switch case分別是這樣:

let name = 'B';
//if else if
if (name === 'A') {
    console.log('a');
} else if (name === 'B') {
    console.log('b');
} else if (name === 'C') {
    console.log('c');
} else {
    console.log('d');
};

//switch case
switch (name) {
    case 'A':
        console.log('a');
        break;
    case 'B':
        console.log('b');
        break;
    case 'C':
        console.log('c');
    default:
        console.log('d');
};

那么我們希望A或B情況輸出1,C情況輸出2,其它情況輸出3呢,switch case其實也能做到:

let name = 'B';
//if else if
if (name === 'A' || name === 'B') {
    console.log(1);
} else if (name === 'C') {
    console.log(2);
} else {
    console.log(3);
};

//switch case
switch (name) {
    case 'A':
    case 'B':
        console.log(1);
        break;
    case 'C':
        console.log(2);
    default:
        console.log(3);
};

當然我想大多數人還是會覺得switch case寫起來賊麻煩,盡管它的可讀性確實比 else if 更高,沒關系,就算作為了解也沒有壞處。

 伍 ❀ 對象配置

條件超過三種,else if 寫起來不太優雅,switch case又覺得麻煩,有沒有更棒的做法呢?我在實際開發遇到過這樣一個情景,我需要根據用戶不同的操作類型對同一份數據進行不同加工,比如新增,修改,刪除等。那么我用else if是這么做的:

function del() {
    //刪除操作
};

function add() {
    //新增
};

function update() {
    //更新
};

function process(operateType) {
    if (operateType === 'del') {
        del()
    } else if (operateType === 'add') {
        add()
    } else if (operateType === 'update') {
        update()
    };
};
process('del');//刪除

一種很棒的做法就是通過對象配置,將你的操作類型作為key,具體操作的函數作為value,像這樣:

function del() {
    //刪除操作
};

function add() {
    //新增
};

function update() {
    //更新
};
let typeFn = {
    'del': del,
    'add': add,
    'update': update
};

function process(operateType) {
    typeFn[operateType]();
};
process('del'); //刪除

怎么樣,有沒有眼前一亮呢?我們將需求升級,現在除了判斷操作type類型外,還得額外附加一個狀態類型,else if是這樣,這里簡單描述下:

function process(operateType, status) {
    if (operateType === 'del' && status === 1) {
        del()
    } else if (operateType === 'add'&& status === 2) {
        add()
    } else if (operateType === 'update'&& status === 3) {
        update()
    };
};

不太優雅,通過對象配置做法,我們其實只用將參數簡單配置就OK了,像這樣是不是更清爽呢:

let typeFn = {
    'del_1': del,
    'add_2': add,
    'update_3': update
};

function process(operateType,status) {
    typeFn[`${operateType}_${status}`]();
};
process('del',1); //刪除

什么,對象配置的調用方式語義化不太明顯?那各位可曾對ES6的map數據結構有了解呢,如果你覺得這樣的調用不太實在,我們再改改,將調用條件與函數配置成map數據,像這樣:

let typeFn = new Map([
    ['del_1', function () {/*do something*/ }],
    ['add_2', function () {/*do something*/ }],
    ['update_3', function () {/*do something*/ }],
]);

function process(operateType, status) {
    typeFn.get(`${operateType}_${status}`)();
};
process('del', 1); //刪除

我們通過map數據的get方法去數據中找到方法執行,這下可讀性總強一點了吧,諸君可否滿意呢?

 陸 ❀ 數組配置

在處理條件判斷時,我們常會遇到條件與對應結果全部已知的情況,比如我們要根據用戶的經驗設置等級頭銜,[0,100)--萌新,[100,200)--騎士,[200,300)--英雄,[300-無限大]--傳說,那么用else if怎么寫已經沒有懸念了:

function youAreMyHero(experience) {
    if (experience < 100) {
        return '萌新';
    } else if (experience < 200 && experience >= 100) {
        return '騎士';
    } else if (experience < 300 && experience >= 200) {
        return '英雄';
    } else if (experience >= 300) {
        return '傳說';
    };
};
let level = youAreMyHero(351); //傳說

對於這種條件與結果已知的情況,我們其實可以通過數組配置的形式將條件結果抽離出來,像這樣:

function youAreMyHero(param) {
    let experience = [300, 200, 100];
    let level = ['傳說', '英雄', '騎士', '萌新'];

    for (let i = 0; i < experience.length; i++) {
        if (param >= experience[i]) {
            return level[i];
        };
    };
    return level[level.length - 1];
};

let level = youAreMyHero(250); //英雄

這么做的好處就是便於管理條件與執行結果,如果后面新增了等級判斷,我們不用去修改業務邏輯中的 else if 語句長度,只用單純維護我們抽離的數據即可。

 柒 ❀ 總

那么到這里,我們大致介紹了五種可取代if else的方式,我們知道短路運算符除了短路求值,還能用於函數調用;三元運算符也不僅僅是處理變量賦值,在return場景結合三元用起來居然如此舒適。

在文章后半段,我們還了解了對象配置,利用map數據結構,以及數據實行來解決特殊場景。我並不推薦為了追求高逼格而犧牲代碼可讀性,但我更希望在你以后的代碼中不僅僅只有if else,那么到這里本文結束。

 參考

[淺析]特定場景下取代if-else和switch的方案

如何無痛降低 if else 面條代碼復雜度

你本可以少寫些 if-else

JavaScript 復雜判斷的更優雅寫法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM