消滅IF ELSE的幾種方式

1. 使用聲名式驗證代替命令式驗證

// Nope
if (!data.name) {
    tip('請輸入您的姓名')
} else if (!data.identify) {
    tip('請輸入您的身份證')
} else if (!data.cardId) {
    tip('請輸入您的借記卡號')
} else if (!data.bankSelect) {
    tip('請選擇借記卡所屬銀行')
} else if (!data.cardTel) {
    tip('請輸入您的預留手機號碼')
} else {
    submitAuthentication()
}
複製代碼
// Yep
import Schema from 'async-validator'    

new Schema({
    name: { type: 'string', required: true, message: '請輸入您的姓名' },
    identify: { type: 'string', required: true, message: '請輸入您的身份證' },
    cardId: { type: 'string', required: true, message: '請輸入您的借記卡號' },
    bankSelect: { type: 'object', required: true, message: '請選擇借記卡所屬銀行' },
    cardTel: { type: 'string', required: true, message: '請輸入您的預留手機號碼' }
}).validate(dataToCheck).then(() => {
    that.submitAuthentication()
}).catch(({ errors, fields }) => {
    // errors是全部錯誤的數組,
    // fields是全部驗證錯誤的字段爲key,相應的錯誤爲value
    console.log(errors)
    // 僅提示第一個錯誤信息,
    // 這裏建議把錯誤信息及時反饋到表單上的每一個字段上
    tip(errors[0].message)
})

// 異步判斷
{
    name: { type: 'string', required: true, message: '請輸入您的姓名' },
    identify: [
        { type: 'string', required: true, message: '請輸入您的身份證' },
        { asyncValidator(rule, value, callback, source, options) {
              api.check(someData).then((data) => {
                data.valid ? callback() : callback(new Error(data.message))
              }).catch(error => {
                callback(new Error(error))
              })
        }}
    ],
    cardId: { type: 'string', required: true, message: '請輸入您的借記卡號' },
    bankSelect: { type: 'object', required: true, message: '請選擇借記卡所屬銀行' },
    cardTel: { type: 'string', required: true, message: '請輸入您的預留手機號碼' }
}
複製代碼

async-validator: github.com/yiminghe/as…html

2. 使用策略模式替代 if...if...if...

本質上第一種方式也屬於策略模式git

參考:juejin.im/post/5bdfef…github

// Nope
const aCase = 'case1'

if(aCase === 'case1') {
  // do sth 
}

if(aCase === 'case2') {
  // do sth 
}

if(aCase === 'case3') {
  // do sth 
}

if(aCase === 'case4') {
  // do sth 
}
複製代碼
// Better, but Nope
switch (status){
case 1:
  sendLog('processing')
  jumpTo('IndexPage')
  break
case 2:
case 3:
  sendLog('fail')
  jumpTo('FailPage')
  break  
case 4:
  sendLog('success')
  jumpTo('SuccessPage')
  break
case 5:
  sendLog('cancel')
  jumpTo('CancelPage')
  break
default:
  sendLog('other')
  jumpTo('Index')
  break
}
複製代碼
// Much better, Yep
const aCase = 'case1'

// 基本類型做爲key
new Map([
  ['case1',()=>{/*do sth*/}],
  ['case2',()=>{/*do sth*/}],
  //...
]).get(aCase)()


// object做爲key
const actions = new Map([
  [{identity:'guest',status:1},()=>{/* functionA */}],
  [{identity:'guest',status:2},()=>{/* functionA */}],
  [{identity:'guest',status:3},()=>{/* functionA */}],
  [{identity:'guest',status:4},()=>{/* functionA */}],
  [{identity:'guest',status:5},()=>{/* functionB */}],
  //...
])

// 正則用法
const actions = ()=>{
  const functionA = ()=>{/*do sth*/}
  const functionB = ()=>{/*do sth*/}
  const functionC = ()=>{/*send log*/}
  return new Map([
    [/^guest_[1-4]$/,functionA],
    [/^guest_5$/,functionB],
    [/^guest_.*$/,functionC],
    //...
  ])
}

const onButtonClick = (identity,status)=>{
  // 過濾某些策略
  let action = [...actions()].filter(([key,value])=>(key.test(`${identity}_${status}`)))
  action.forEach(([key,value])=>value.call(this))
}

複製代碼

Map的key能夠是任意類型的數據編程

3. 使用責任鏈模式替代 if / else,if / else, ...

// Nope
// 溫度爲0時輸出水結冰了
if(temp === 0) {
    return 'water freezes at 0°C' 
// 溫度爲100時輸出
} else if(temp === 100) {
    return 'water boils at 100°C'
} else { 
    return 'nothing special happens at ' + temp + '°C'
}

複製代碼

使用函數式編程庫Ramda:api

// Yep
const fn = R.cond([
  [R.equals(0),   R.always('water freezes at 0°C')],
  [R.equals(100), R.always('water boils at 100°C')],
  [R.T,           temp => 'nothing special happens at ' + temp + '°C']
]);
fn(0); //=> 'water freezes at 0°C'
fn(50); //=> 'nothing special happens at 50°C'
fn(100); //=> 'water boils at 100°C'
複製代碼
  • 必定程度上,Map的正則用法也能夠實現責任鏈模式,不過Ramda更簡潔。
  • 值得一提的是,Ramda還有許多很是實用的用法,讓咱們的代碼更簡潔,我的認爲本質上是更趨向語義化
  • 嘗試用Ramda提供的函數來做爲你代碼中最基本的元素,而不是用最原生JS
  • 固然,物極必反,沒必要追求到處都使用函數式編程,合適永遠是不錯的

Ramda: ramda.cn/docs/#cond數組

關於函數式編程

函數式編程的本質是Pointfree的概念,細讀這篇文章便能明白爲何函數式編程會出現app

Pointfree: www.ruanyifeng.com/blog/2017/0…異步

相關文章
相關標籤/搜索