浅谈Js复杂判断的优雅写法

205 阅读4分钟

仅有两种可能

  • 当判断只有两种可能,一般选择 if else 就足够了

if else

// if else
if (name === 'ZhangSan') {
    ...
} else {
    ...
}

三元

接上面,话说到,如果当前存在单语句、赋值,直接用三元更简洁

// 当前只有张三是超管 其他人都不是
const admin = name === 'ZhangSan' ? true : false

// 一般会直接把后面的 ? true : false 直接去掉,本身判断就是布尔值
const admin = name === 'ZhangSan'

||、&&、??

除了三元,特定情况用 ||、&& 运算符, 更简洁, 可作为赋值或判断

||

// 当值 为 null、undefined、0、""、false、NaN 时,回传后面的值

const num = 1 || 2  // 输出为: 1
const num = 0 || 2  // 输出为: 2


// 也可以预备多个选择, 从左到右, 回传第一个为true的值, 若全为false, 则回传最后一个值

const num = 1 || 2 || 3  // 1
const num = 0 || 15  // 15
const num = 0 || undefined || null  // null

&&

// 从左到右, 回传第一个是false的值, 若全为true,则回传最后一个值

const num = 1 && 0 && 3  // 0
const num = 1 && 2 && 3  // 3

??

// 当且仅当运算符左侧为 null 或者 undefined 时, 回传右侧的值

const name = null ?? 'ZhangSan' // 'ZhangSan'
const name = 0 ?? 'ZhangSan' // 0

注: **||?? 区别是: **

?? 是 当且仅当 左侧 null 或者 undefined

|| 是 左侧 null、undefined、0、""、false、NaN 任意一个 时


超过两种可能

一般为了代码简洁易懂, 超过2种可能的多种可能, 最好不要 if...else if...else if...else 这种写法, 可使用 switch...case

不同情况不同分析:

  • 多种情况对应同一种情况
if (a === 1 || a === 2 || a === 3) {
    console.log('执行')
}

// 替换成

if ([1, 2, 3].includes(a)) {
    console.log('执行')
}
  • 多种情况对应多种情况
  1. 对应不同事件,对应不同行为
let arr = []

if (event === 'mousedown') {
    arr = ['mousedown', mousedownFn]
} else if (event === 'mouseenter') {
    arr = ['mouseenter', mounseenterFn]
} else if (event === 'mouseleave') {
    arr = ['mouseleave', mouseleaveFn]
}


// 替换成


let arr = []

const obj = {
    mousedown: ['mousedown', mousedownFn],
    mouseenter: ['mouseenter', mounseenterFn],
    mouseleave: ['mouseleave', mouseleaveFn]
}

arr = obj[event] || ['other', otherFn]


// 更清爽: es6 Map对象 写法

const map = new Map(
    [
        ['mousedown', ['mousedown', mousedownFn]],
        ['mouseenter', ['mouseenter', mounseenterFn]]
        ['mouseleave', ['mouseleave', mouseleaveFn]]
        ['other', ['other', otherFn]]
    ]
)

arr = map.get(event) || map.get('other')

注: Map 对象Object 对象 区别:

  1. 一个对象通常都有自己的原型,所以一个对象总有一个prototype
  2. 一个对象的键只能是字符串或者Symbols, 但一个Map对象的键可以是任意值
  3. 键值对个数
  • Map对象的键值对个数: map.size
    
  • Object对象的键值对个数: Object.keys(obj).length
    
  1. 对应不同状态,对应不同文本
// status 0 待付款 1 待发货 2 待收货 3 待评价 4 退款
let text = ''

// if else
if (status === 0) {
    text = '待付款'
} else if (status === 1) {
    text = '待发货'
} else if (status === 2) {
    text = '待收货'
} else if (status === 3) {
    text = '待评价'
} else if (status === 4) {
    text = '退款'
}

// switch case
switch {
    case 0:
        text = '待付款'
        break
    case 1:
        text = '待发货'
        break
    case 2:
        text = '待收货'
        break
    case 3:
        text = '待评价'
        break
    case 4:
        text = '退款'
        break
    default:
        text = '--'
        break
}

// 下标 index
const arr = [待付款,待发货,待收货,待评价,退款]
text = arr[status] || '--'

上面例子为数值情况, 若 不是数值 或者 数值过大

// 数值过大

// status 110 待付款 111 待发货 112 待收货 113 待评价 114 退款

const obj = {
    110: '待付款',
    111: '待发货',
    112: '待收货',
    113: '待评价',
    114: '退款',
}

text = obj[status] || '--'


// 非数值

// status a 待付款 b 待发货 c 待收货 d 待评价 e 退款

const obj = {
    a: '待付款',
    b: '待发货',
    c: '待收货',
    d: '待评价',
    e: '退款',
}

text = obj[status] || '--'

问题升级

现需要 判断身份 再 判断状态

// identity - status

if (identity == 'master') {
    if (status === 0) {
        // do sth
    } else if (status === 1) {
        // do sth
    } else if (status === 2) {
        // do sth
    } else if (status === 3) {
        // do sth
    } else if (status === 4) {
        // do sth
    }
} else if (identity == 'guest') {
    if (status === 0) {
        // do sth
    } else if (status === 1) {
        // do sth
    } else if (status === 2) {
        // do sth
    } else if (status === 3) {
        // do sth
    } else if (status === 4) {
        // do sth
    }
}


// 更清爽: es6 Map对象 写法

const map = new Map(
    [
        ['master_0', () => { // do sth }],
        ['master_1', () => { // do sth }],
        ['master_2', () => { // do sth }],
        ['master_3', () => { // do sth }],
        ['master_4', () => { // do sth }],
        ['guest_0', () => { // do sth }],
        ['guest_1', () => { // do sth }],
        ['guest_2', () => { // do sth }],
        ['guest_3', () => { // do sth }],
        ['guest_4', () => { // do sth }],
        ['other', () => { // do sth }],
    ]
)

let action = map.get(`${identity}_${status}`) || map.get('other')


// 更清爽: Object 对象 写法

const obj = {
    master_0: () => { // do sth },
    master_1: () => { // do sth },
    ...
}

let action = obj[`${identity}_${status}`] || obj['other']


// es6 Map对象 拆 identity - status

const map = new Map(
    [
        [{ identity: 'master', status: 0 }, () => { // do sth }],
        [{ identity: 'master', status: 1 }, () => { // do sth }],
        ...
        [{ identity: 'guest', status: 0 }, () => { // do sth }],
        [{ identity: 'guest', status: 1 }, () => { // do sth }],
        ...
    ]
)

let action = [...map].filter(([key, value]) => (key.identity == identity && key.status == status))

action.forEach(([key, value]) => value.call(this))

注: 若 status 0 - 3 逻辑 do sth 一致

// 用正则

const obj = () => {
    const fnA = () => {}
    const fnB = () => {}
    return new Map(
    [
        [/^master_[0-4]$/, fnA],
        [/^master_5$/, fnB],
        ...
    ]
}

总结:

  1. if else

  2. switch case

  3. 三元

  4. || && ??

  5. 一元判断时:存到Object里

  6. 一元判断时:存到Map里

  7. 多元判断时:将条件拼接成字符串存到Object里

  8. 多元判断时:将条件拼接成字符串存到Map里

  9. 多元判断时:将条件存为Object存到Map里

  10. 多元判断时:将条件写作正则存到Map里