[Анализ] Альтернативы оптимизации if-else в определенных сценариях (2)

JavaScript структура данных

Есть два и есть два, есть два и три. Превратите неизвестное в известное и станьте своим собственным знанием

предисловие

Давным-давно я опубликовал статью:[Анализ] Схемы замены if-else и переключения в конкретных сценариях, но сценариев использования if-else не так уж и мало как вышеперечисленных статей, сценариев много, и сегодня я напишу, что можно заменить или оптимизировать в разработкеif-elseместо действия.

Акцент на замену или оптимизацию здесьif-else, осуществляется по определенному сценарию. Цель состоит в том, чтобы улучшить код в конкретных сценариях и сделать его кратким. Повышение удобочитаемости, ремонтопригодности и возможности повторного использования кода. еслиif-elseИспользуемые сценарии относительно просты или оптимизированы.if-elseТогда это плохо скажется на коде. Не рекомендуется использовать другие решения для замены или оптимизации, не писатьif-elseНе написав, вы не сможете оптимизировать ради оптимизации.

1. Запрос диапазона

Например, нарисуйте диапазон выигрышных номеров, диапазон выигрышных номеров 9-12, 14-18, а затем вам нужно определить, выиграл ли номер в лотерею, логика очень проста для достижения

let num1= 15
let num2= 13
if((num1>=9 && num1<=12)||(num1>=14 && num1<=18)){
     // 中奖了
}
if((num2>=9 && num2<=12)||(num2>=14 && num2<=18)){
     // 中奖了
}

Это вроде бы не проблема записать, если в будущем спрос изменится, выигрышное число будет не 9-12 или 14-18. Скорее 10-14 или 18-20. Это изменит исходную логику кода

if((num1>=10 && num1<=14)||(num1>=18 && num1<=20)){
     // 中奖了
}

Или есть другие требования, например, выигрышный номер 9-12, 14-18, 20-22 или 26-30. Все равно придется менять логику if-else

if((num1>=9 && num1<=12)||(num1>=14 && num<=18)||(num1>=20 && num1<=22)||(num2>=26 && num1<=30)){
     // 数字在范围内
}

Теперь вы можете использовать некоторые для инкапсуляции функции, вам нужно инкапсулировать ее только один раз, и если объем будущих требований изменится, вы можете

function handleCheckRange(num, ...ranges){
    return ranges.some(item=>num>=item[0]&&num<=item[1])
}
handleCheckRange(num1,[9,12],[14,18]) //true
handleCheckRange(num2,[9,12],[14,18]) //false
handleCheckRange(num2,[10,14],[18,20]) //true
handleCheckRange(num2,[9,12],[14,18],[20,22],[26,30]) //false

1. Некоторые люди могут подумать, что если есть другое требование, условие суждения не >= или , или =? такhandleCheckRangeЕго также необходимо изменить. В этом случае необходимо изменить этот метод при возникновении других условий суждения. Но изменить этот метод несложно, просто инкапсулируйте его напрямую

2. Если в условиях оценки слишком много изменений, метод инкапсуляции должен быть совместим с другими условиями оценки.Вы можете обратиться к моим примечаниям:Упражнение 5. Моделирование реализации открытых и закрытых интервалов, здесь обсуждаться не будет.

2. Множественные и условия

Я считаю, что каждый столкнется с проблемами, которые могут иметь комбинацию нескольких состояний.

Например, если есть бонусные баллы за участие в горячих распродажах, статус активности (status), предварительный нагрев (status=1),в ходе выполнения(status=2). тип пользователя(type) также делится на обычных пользователей (type=1) вип пользователь (type=2)

Правила таковы: 1. Участвуйте в активности во время разминки, VIP-пользователи получат 1000 баллов, а обычные пользователи — 700 баллов. 1. Участвуйте в текущей активности, VIP-пользователи получат 800 баллов, а обычные пользователи — 300 баллов.

Это было написано раньше

let status=1
let type=2
if(status===1){
     if(type===1){
           console.log('普通用户在预售中参与活动,赠送700积分')
    }
    else if(type===2){
           console.log('vip用户在预售中参与活动,赠送1000积分')
    }
}
else if(status===2){
     if(type===1){
           console.log('普通用户在进行中参与活动,赠送300积分')
    }
    else if(type===2){
           console.log('vip用户在进行中参与活动,赠送800积分')
    }
}

// 或者

if(status===1&&type===1){
    console.log('普通用户在预售中参与活动,赠送700积分')
}
else if(status===1&&type===2){
    console.log('vip用户在预售中参与活动,赠送1000积分')
}
else if(status===2&&type===1){
    console.log('普通用户在进行中参与活动,赠送300积分')
}
else if(status===2&&type===2){
    console.log('vip用户在进行中参与活动,赠送800积分')
}

Но теперь вы можете использовать метод записи obj, так что, если у вас возникнут какие-либо условия для изменения в будущем, просто измените конфигурацию obj напрямую.

let obj={
   'status=1&type=1':'普通用户在预售中参与活动,赠送700积分',
   'status=1&type=2':'vip用户在预售中参与活动,赠送1000积分',
   'status=2&type=1':'普通用户在进行中参与活动,赠送300积分',
   'status=2&type=2':'普通用户在进行中参与活动,赠送800积分'
}

console.log(obj[`status=${status}&type=${type}`])

3. Множественное или условие

Например, введите название города и выведите название провинции.

let city='广州'
if(city==='广州'||city==='佛山'){
    console.log('广东')
}
else if(city==='海口'||city==='三亚'){
    console.log('海南')
}

Недостатком этого является то, что еслиif-elseПо мере увеличения числа код будет увеличиваться, а условия оценки станут очень длинными.Еще одна проблема заключается в том, что стиль может быть неоднородным.

Оптимизируйте другими способами метод первый

let arr=[
    {
        city:'广州',
        province:'广东'
    },
    {
        city:'佛山',
        province:'广东'
    },
    {
        city:'海口',
        province:'海南'
    },
    {
        city:'三亚',
        province:'海南'
    }
]
console.log(arr.filter(item=>item.city===city)[0].province)//广东

Способ второй

let city='广州'
let obj={
    '广州':'广东',
    '佛山':'广东',
    '海口':'海南',
    '三亚':'海南',
}
console.log(obj[city])// 广东

Увидев, что Гуандун и Хайнань были написаны так много раз, каждый может быть подавлен.В провинции 20 городов, и их нужно написать 20 раз.Некоторые люди могут думать о городах как о городах.key, а затем оценивать входящиеcityВы вkeyВнутри код выглядит следующим образом.

let city='广州'
let obj={
    '广州,佛山':'广东',
    '海口,三亚':'海南',
}
for(let key in obj){
    if(key.includes(city)){
        console.log(obj[key])
        break
    }
}
//广东

Но вылезают и недостатки, т. е. вышеописанный способ имеетbug, выводится только одно слово названия города, а также может быть выведена соответствующая провинция.

let city='州'
let obj={
    '广州,佛山':'广东',
    '海口,三亚':'海南',
}
for(let key in obj){
    if(key.includes(city)){
        console.log(obj[key])
        break
    }
}
//广东

Чтобы решить эту проблему, есть два пути, один из которых состоит в том, чтобы поставитьkeyПреобразуйте в массив, а затем оцените или используйтеMap

// 方式一:把 key 转成数组再判断

let city='广州'
let obj={
    '广州,佛山':'广东',
    '海口,三亚':'海南',
}
let keys=[]
for(let key in obj){
    keys=key.split(',')
    if(keys.includes(city)){
        console.log(obj[key])
        break
    }
}


//  方式二:使用Map
let city='广州'
let map=new Map([
     [['广州','佛山'],'广东'],
     [['海口','三亚'],'海南'],
])
for (let key of map.keys()) {
  if(key.includes(city)){
        console.log(obj[key])
        break
    }
}
//广东

4. Неправильное если-иначе, если

В этом случаеif-elseifПравил не найти. Например, необходимо проводить мероприятия по отбору студентов на получение стипендии.

1. Комплексная оценка качества учащихся (quality>=90) 90 или выше, со средним баллом 4,5 или выше, чтобы стать первоклассным кандидатом на получение стипендии.

2. Учащиеся с общим баллом качества 80 или выше (quality>=80), со средним баллом не менее 2,5 по каждому предмету, чтобы стать кандидатом на получение стипендии второго класса.

3. Общий балл качества обучающихся должен быть не ниже 75 (quality>=75), получил другие награды и награды и стал кандидатом на получение стипендии третьего класса.

let studentInfo={
    name:'守候',
    chinese:4.6,
    math:4.7,
    english:4,
    computer:4.8,
    quality:93,
    prizes:['搬砖','扫地']
}
let subjectAll=['chinese','math','english','computer']
function handle (student,subject) {
    function getAverage(){
        let sum=0
        subject.forEach(item=>sum+=student[item])  
        return sum/subject.length
    }
    function checkScore(){
      return subject.every(item => student[item]>2.5)
    }  
    if(student.quality>=90&&getAverage()>4.5){
        console.log('成为一等奖学金候选人')
        // 其他代码
    }
    else if(student.quality>=80&&checkScore()){
        console.log('成为二等奖学金候选人')
        // 其他代码
    }
    else if(student.quality>=75&&student.prizes.length>0){
        console.log('成为三等奖学金候选人')
        // 其他代码
    }
}

handle(studentInfo,subjectAll) //成为一等奖学金候选人

Код выглядит очень простым и завершенным, но в реальной разработкеif-elseifколичество уровней, каждыйif-elseifЛогика суждения и код, выполняющий внутри нее операцию, выходят далеко за рамки этого примера. ТакhandleКод для этого метода будет длинным, а сам метод станет огромным. Это сильно влияет на удобочитаемость, ремонтопригодность и возможность повторного использования кода. Если требования меняются, необходимо уточнить логику всей функции.

Приведенный выше код в основном нуждается в обработкеif-elseif. но этиif-elseНет правил, которые можно найти, поэтому все можно извлечь только по отдельности, и все они инкапсулированы в функции.

function handle (student,subject) {
    function getAverage(){
        let sum=0
        subject.forEach(item=>sum+=student[item])  
        return sum/subject.length
    }
    function checkScore(){
      return subject.every(item => student[item]>2.5)
    }
    let rules=[
        {
            rule(){
                return student.quality>=90&&getAverage()>4.5
            },
            fn(){
                console.log('成为一等奖学金候选人')
                // 其他代码
            }
        },
        {
            rule(){
                return student.quality>=80&&checkScore()
            },
            fn(){
                console.log('成为二等奖学金候选人')
                // 其他代码
            }
        },
        {
            rule(){
                return student.quality>=75&&student.prizes.length>0
            },
            fn(){
                console.log('成为三等奖学金候选人')
                // 其他代码
            }
        }
    ]
    for(let item of rules){
        if(item.rule()){
            item.fn()
            // 执行完函数马上返回,不再执行下一次循环
            return
        }
    }
}

Это пока естьitem.fn()Если он выполнен, значит, студент стал кандидатом, просто верните его.

Таким образом, код также полностью соответствует предыдущемуif-elseifлогика. У некоторых могут возникнуть сомнения, что код не уменьшился, а увеличился, но на самом деле этот код был разбит на куски, а читабельность и ремонтопригодность улучшены, если есть необходимость что-то там изменить, мы тоже не будем нужно возиться со всей функцией, просто изменитьrules.

5. Несколько, если

В другом случае несколькоif-elseсвязанный с исполняемым кодом,

Например, есть страница, которая может отображать следы, записанные пользователем, а также позволяет пользователю выбрать запись собственных следов.Областью записи может быть провинция, город или район. Затем код должен реализовать провинцию и город, связь с несколькими вариантами выбора. Логика такова: если вы выбираете провинцию, вы можете не выбирать город, но если вы выбираете город, вы выбираете провинцию и так далее. Ниже приведен простой псевдокод.

function initPostion(){
    //所有省份列表
    let provinceList=['广东','广西','海南','....'] 
    //已选省份下辖的所有城市
    let cityList=[] 
    //已选城市下辖的所有区
    let districtList=[] 
    
    //已选择省份
    let selectedProvinces=['广东','广西']
    //已选择城市
    let selectedCitys=['广州']
    //已选择区
    let selectedDistricts=['天河区']
    
    //如果选了省份
    if (selectedProvinces.length>0) {
        //根据 selectedProvinces 获取 cityList 的逻辑
        //其他代码
    }
    if (selectedCitys.length>0) {
        //根据 selectedCitys 获取 districtList 的逻辑
        //其他代码
    }
    
    //其他初始化显示的逻辑
}

Как только псевдокод написан, некоторые разработчики должны были увидеть проблему. всеifВсе они связаны друг с другом, и логика кода в if может быть намного длиннее. Если в дальнейшем спрос изменится, требуется выбрать страну, затем провинцию или город, либо после выбора района можно также выбрать город и деревню. К тому времениifстанет больше,initPostionОбщий код может стать огромным. Обслуживание может быть трудоемким и подверженным ошибкам.

Чтобы решить эту проблему, вы можетеifразделить на функции

function initPostion(){
    //所有省份列表
    let provinceList=['广东','广西','海南','....'] 
    //已选省份下辖的所有城市
    let cityList=[] 
    //已选城市下辖的所有区
    let districtList=[] 
    
    //已选择省份
    let selectedProvinces=['广东','广西']
    //已选择城市
    let selectedCitys=['广州']
    //已选择区
    let selectedDistricts=['天河区']
    
    let handleObj={
        provinces(){
            //如果选了省份
            if (selectedProvinces.length>0) {
                //根据 selectedProvinces 获取 cityList 的逻辑
                //其他代码
            }
        },
        city(){
            if (selectedCitys.length>0) {
                //根据 selectedCitys 获取 districtList 的逻辑
                //其他代码
            }
        }
    }
    
    let handleFns=['provinces','city']
    
    for(let fnName of handleFns){
        handleObj[fnName]()
    }
    
    //其他初始化显示的逻辑
}
    

Может показаться, что кода много, но управлять им будет проще, чем исходным решением.ifВсе они разбиты на функции, если вам нужно изменить определенный фрагмент кода, просто измените определенный фрагмент кода, и вам не нужно менять другие коды. Если есть изменение в спросе, это должно изменитьсяhandleObjфункция свойства , иhandleFnsпорядок .

Ссылка на ссылку

[Анализ] Схемы замены if-else и переключения в конкретных сценариях

Более элегантный способ написания сложных суждений в JavaScript

резюме

хорошо, оif-elseНа этом вторая статья о замене и оптимизации схемы . Здесь снова заменить и оптимизироватьif-elseЗаявление, рекомендуется использовать конкретную схему в конкретном сценарии. Помните, что нельзя заменять ради замены, не оптимизировать ради оптимизации.

Если я найду другой выигрыш в будущем, я напишу статью как можно скорее. Если у всех есть какие-либо предложения, мнения или ошибки в статье, пожалуйста, оставьте сообщение в области комментариев для улучшения.

------------------------- Великолепная разделительная линия --------------------

Если вы хотите узнать больше и пообщаться со мной, добавьте меня в WeChat. Или обратите внимание на мой паблик WeChat: В ожидании книжного магазина