总结一下前端if..else...的几个优化方式

155 阅读3分钟

先上总结:

  • 条件少的情况,都可以。
  • 条件多的情况,使用switch或者二维数组代替if..else。使用switch的理由:
    1. 美观上,switch看起来更有条理性;
    2. 性能上,条件多时,switch性能优于if...else。具体原因:switch底层在编译时候生成跳表,空间换时间提高条件查询速度;而if...else则是条件挨个匹配判断。

switch与if...else区别:

  1. switch条件判断只能处理条件为常量的情况,对于if(condition > 0 && condition < 100)这种情况无法处理,只能用if...else
  2. switch底层是跳表,优化了查询速度,而if...else没有用到优化的数据结构存储,故性能肯定比不上switch。在编译阶段,switch会生成跳表,等到程序执行可以快速查找到符合条件的分支;而if...else在程序执行的时候还要一层一层分支的判断。
  3. 条件多时,switch看起来逻辑更清晰

判断条件少的情况:

condition && doSth()
condition ? doSth() : doElse()

判断条件多的情况:

一、如果条件判断可以归纳为键值对,可以用switch或者策略模式

switch方式:

switch(true)
    case condition1: 
        handler1()
        break;
    case condition2: 
        handler2()
        break;
    case condition3: 
        handler3()
        break;

策略模式

const handleMap = {
    condition1: handler1,
    condition2: handler2,
    condition3: handler3
}

const handleResult = ()=> {
    handlerMap[condition]
}

二、 如果判断条件是按照范围之类复杂的条件,那么可以用责任链模式或者二维数组

    if(0 < point < 60) {
        handler1()
    } else if(61 < point < 80) {
        handler2()
    } else if(81 < point < 100) {
        handler3()
    } else if(point === 100) {
        handler3()
    }

方法一:责任链模式:
以上的方式是用穷举的方式在配置数据中查找到相对应的处理方法,而责任链模式就是将整个处理的逻辑改写成一条责任传递链,请求在这条链上传递,直到有一个对象处理这个请求。 比如:

class Point1 {
    handler(condition) {
        if (0 < condition && condition < 60) {
            handler1()
        } else {
            return this.point.handler(condition)
        }
    }
    setPoint(p) {
        this.point = p
    }
}

class Point2 {
    handler(condition) {
        if (61 < condition && condition < 80) {
            handler2()
        } else {
            this.point.handler(condition)
        }
    }
    setPoint(p) {
        this.point = p
    }
}

class Point3 {
    handler(condition) {
        if (81 < condition && condition < 100) {
            handler3()
        } else {
            this.point.handler(condition)
        }
    }
    setPoint(p) {
        this.point = p
    }
}

class Point4 {
    handler(condition) {
        if (condition === 100) {
            handler4()
        } else {
            this.point.handler(condition)
        }
    }
    setPoint(p) {
        this.point = p
    }
}

const point1 = new Point1()
const point2 = new Point2()
const point3 = new Point3()
const point4 = new Point4()
point1.setPoint(point2)
point2.setPoint(point3)
point3.setPoint(point4)

const point = 99
// 由第一层处理逻辑开始处理
point1.handler(point)

方法二:二维数组:
二维数组相当于手动构造映射关系,优化查询速度。
将条件作为数组的第一项,将子数组的第一个元素-第二个元素写成类似于key-value映射,find方法筛选时可以选出符合条件的子数组。

const pointMap = [
    [
        // 箭头函数,相当于(point)=> return point > 0 && point < 60,返回boolean方便find查询
        (point)=> point > 0 && point < 60,
        () => handler1()
    ],
    [
        (point)=> point > 61 && point < 80,
        () => handler2()
    ],
    [
        (point)=> point >= 80 && point < 100,
        () => handler3()
    ],
    [
        (point)=> point === 100,
        () => handler4()
    ]

]
    
function getPoint(point) {
    // 获取符合条件的子数组
    const getPointHandler = pointMap.find(item => item[0](point))
    
    // 子数组存在则运行第二个元素
    getPointHandler ? getPointHandler[1]() : console.log('error');

}

// 调用
getPoint(86)