JS 中 if / if...else...替換方式

if/if...else...替換方式

說說爛大街的if/if...else...,程序中用得最多的流程判斷語句。javascript

對着曾經滿屏的if/if...else...,心想能不能搞點事情,折騰點浪花浪裏呀浪。html

對頂着「這個需求很簡單,怎麼實現我無論,明天上線」的程序猿,答案必須YES。java

"Write Less, Do More",學習進步的本質就是爲了更有效率地偷懶。算法

廢話說完,直接上方法彙總,讓咱們來一窺究竟:segmentfault

switch改寫if

// if 版本
var a = 1;
if(a > 1 && a < 5) {
    return 1
} else if(a > 5 && a < 10){
    return 5
}else{
    return 10
}

// switch 改版
switch(true){
    case (a > 1 && a < 5):
        return 1
    case (a > 5 && a < 10):
        return 5
    default:
        return 10
}

以上代碼的switch...case...的用法實際使用很少,僅供參考。
通常case爲常量時switch...case...用得較多。設計模式

選擇分支較多時,建議選用switch…case可提升程序的效率,但switch...case不足的地方在於只能處理字符或者數字類型的變量,if…else更加靈活,可用於判斷表達式是否成立,好比if(a+b>c),if…else的應用範圍更廣。api

三元運算符改寫if

// if 版本
if (bool) {
    value = 1;
} else {
    value = 2;
}

// 三元運算符 版本
value = bool ? 1 : 2;
// 三元預算符 多個運算須要括號包裹 此處用了逗號表達式
return typeof foo === 'object'?(console.log(1),1):(console.log(2),2);

優勢:代碼簡化,更加清爽,write lessapp

缺點:複雜的三元運算符可讀性較差,需友好註釋less

TIPS: 三元運算符後面不能帶returndom

// 錯誤用法,運算符號後不能帶return
bool ? return 1 : return 2;

邏輯判斷 and(&&)和or(||) 改寫if

原理:利用邏輯判斷的短路運算來實現

短路: && 中第一個表達式爲假就不會去處理第二個表達式, || 則相反
// if爲真
if (bool) {
    value = getYes();
}
// &&改版
bool && (value = getYes());

// if爲假
if (!bool) {
    value = getNo();
}
bool || (value = getNo());

優勢:代碼簡化,更加清爽,write less

缺點:適用於簡單判斷邏輯,複雜的判斷運算可讀性較差,需友好註釋

TIPS:適用於沒有else的場景, 邏輯運算符後面不能帶return

// 錯誤用法,運算符號後不能帶return
boll || return true;

知識點插播 —— (1)

  1. 三元運算符和邏輯運算符都有一層return做用,但不可做用於函數return語句,因此像如下這種用法都是錯誤的;
// 錯誤用法
function getResult(value) {
    value ? 'yes' : 'no';
}
var result = getResult(true); // 並不會有值返回
  1. js邏輯運算中,0/""/null/false/undefined/NaN都會判爲false,其它都爲true
  2. 不少開源代碼中可見if(!!attr),爲何不直接寫if(attr), 其實這是一種更嚴謹的寫法,!!attr會強制轉化爲boolean類型。typeof !!attr == truetypeof attr == true 更加嚴謹。

對象屬性

// if版本
if (a == 1) {
    return 'one';
} else if (a == 2) {
    return 'two';
} else if (a == 3) {
    return 'three';
} else {
    return '';
}

// 對象屬性 改版
var ret = {
    1: 'one',
    2: 'two',
    3: 'three'
};
return ret[a] ? ret[a] : '';

TIPS:

  1. 判斷值需爲肯定值,如== ,其它如>=/<=/>/<不適用
  2. 條件做爲對象屬性,須要注意對象屬性的讀取方式

知識點插播 —— (2)

JS的命名規則(變量的命名規則)
  • 標識符只能由字母、數字、下劃線和‘$’組成
  • 數字不能夠做爲標識符的首字符
對象屬性的命名規則
  • 經過[]操做符爲對象添加屬性時,屬性名能夠是任何字符串(包括只包含空格的字符串和空字符串);
  • 經過.操做符爲對象添加屬性時,屬性名必須是合法的標識符名稱;
  • 若是屬性名包含非法的標識符字符,則只能採用obj[「propertyName」]的形式;
  • 若是屬性名是合法的標識符,讀取時可採用obj.propertyNameobj[「propertyName」]的形式;

策略模式

策略模式:定義一系列的算法,把它們一個個封裝起來,目的就是將算法的使用與算法的實現分離開來

如下爲常見的表單驗證,用策略模式來構建,替換if...else的方式

// html
<form id = "registerForm" method="post" action="http://xxxx.com/api/register">
    用戶名:<input type="text" name="userName">
    密碼:<input type="text" name="password">
    手機號碼:<input type="text" name="phoneNumber">
    <button type="submit">提交</button>
</form>

// js
// 策略對象
var strategies = {
    isNoEmpty: function (value, errorMsg) {
        if (value === '') {
            return errorMsg;
        }
    },
    isNoSpace: function (value, errorMsg) {
        if (value.trim() === '') {
            return errorMsg;
        }
    },
    minLength: function (value, length, errorMsg) {
        if (value.trim().length < length) {
            return errorMsg;
        }
    },
    maxLength: function (value, length, errorMsg) {
        if (value.length > length) {
            return errorMsg;
        }
    },
    isMobile: function (value, errorMsg) {
        if (!/^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|17[7]|18[0|1|2|3|5|6|7|8|9])\d{8}$/.test(value)) {
            return errorMsg;
        }                
    }
}

// 驗證類
var Validator = function() {
    this.cache = [];
}
Validator.prototype.add = function(dom, rules) {
    var self = this;
    for(var i = 0, rule; rule = rules[i++];) {
        (function(rule) {
            var strategyAry = rule.strategy.split(':');
            var errorMsg = rule.errorMsg;
            self.cache.push(function() {
            var strategy = strategyAry.shift();
            strategyAry.unshift(dom.value);
            strategyAry.push(errorMsg);
            return strategies[strategy].apply(dom, strategyAry);
            })
        })(rule)
    }
};
Validator.prototype.start = function() {
    for(var i = 0, validatorFunc; validatorFunc = this.cache[i++];) {
        var errorMsg = validatorFunc();
        if (errorMsg) {
            return errorMsg;
        }
    }
};

// 調用代碼
var registerForm = document.getElementById('registerForm');

var validataFunc = function() {
    var validator = new Validator();
    validator.add(registerForm.userName, [{
        strategy: 'isNoEmpty',
        errorMsg: '用戶名不可爲空'
    }, {
        strategy: 'isNoSpace',
        errorMsg: '不容許以空白字符命名'
    }, {
        strategy: 'minLength:2',
        errorMsg: '用戶名長度不能小於2位'
    }]);
    validator.add(registerForm.password, [ {
        strategy: 'minLength:6',
        errorMsg: '密碼長度不能小於6位'
    }]);
    validator.add(registerForm.phoneNumber, [{
        strategy: 'isMobile',
        errorMsg: '請輸入正確的手機號碼格式'
    }]);
    var errorMsg = validator.start();
    return errorMsg;
}

registerForm.onsubmit = function() {
    var errorMsg = validataFunc();
    if (errorMsg) {
        alert(errorMsg);
        return false;
    }
}
  • 第一個部分是一組策略類,策略類封裝了具體的算法,並負責具體的計算過程;
  • 第二個部分是環境類Context,該Context接收客戶端的請求,隨後把請求委託給某一個策略類;

優勢:

  1. 有效避免多重條件選擇語句
  2. 提供了對外開放 - 封裝原則的完美支持,將方法封裝在獨立的strategy中,使得它們易於切換、易於理解、易於擴展。
  3. 複用性

缺點:

  1. 增長了策略類/對象的使用
  2. 使用策略模式,必須先了解全部的strategy,違反了最少知識原則

參考資料

  1. JavaScript設計模式之策略模式
  2. js減小if語句的技巧
  3. js對象屬性的命名規則
  4. javascript中||和&&代替if
做者:以樂之名 本文原創,有不當的地方歡迎指出。轉載請指明出處。
相關文章
相關標籤/搜索