Когда мы пишем код JS, мы часто встречаем сложные логические суждения. В целом, если / else или переключатель можно использовать для реализации нескольких условных суждений, но возникнет проблема: поскольку логическая сложность увеличивается, IF / Enter и переключатель в коде станет все более раздутым. Эта статья займет вас, чтобы попытаться написать более элегантную логику суждения.
Например, следующий код:
const onButtonClick = (status) => {
if (status == 1) {
sendLog('processing')
jumpTo('IndexPage')
} else if (status == 2) {
sendLog('fail')
jumpTo('FailPage')
} else if (status == 3) {
sendLog('fail')
jumpTo('FailPage')
} else if (status == 4) {
sendLog('success')
jumpTo('SuccessPage')
} else if (status == 5) {
sendLog('cancel')
jumpTo('CancelPage')
} else {
sendLog('other')
jumpTo('Index')
}
}
Вы можете увидеть логику нажатия этой кнопки в коде. Сделайте две вещи в зависимости от статуса активности, отправьте записи журнала и перейдите на соответствующую страницу. Легко подумать, что этот код можно было бы переписать с помощью switch следующим образом:
const onButtonClick = (status) => {
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
}
}
Что ж, это выглядит понятнее, чем иерархия if/else.Внимательные читатели также могут найти небольшую хитрость: когда логика случая 2 и случая 3 одинакова, можно опустить предыдущий код обработки логики, и случай 2 автоматически выполнится с Логика случая 3.
Однако есть более простой способ записи:
const actions = {
'1': ['processing', 'IndexPage'],
'2': ['fail', 'FailPage'],
'3': ['fail', 'FailPage'],
'4': ['success', 'SuccessPage'],
'5': ['cancel', 'CancelPage'],
default: ['other', 'Index'],
}
const onButtonClick = (status) => {
let action = actions[status] || actions['default'],
logName = action[0],
pageName = action[1]
sendLog(logName)
jumpTo(pageName)
}
Вышеприведенный код действительно выглядит относительно чистым Ум этого метода заключается в том, что он использует условие оценки в качестве имени свойства объекта и логику обработки в качестве значения свойства объекта. Когда кнопка нажата, этот метод особенно подходит для случая оценки состояния отдельного элемента, то есть логическая оценка выполняется посредством поиска атрибутов объекта.
Этот метод хорош, но есть ли другой способ его закодировать? немного!
const actions = new Map([
[1, ['processing', 'IndexPage']],
[2, ['fail', 'FailPage']],
[3, ['fail', 'FailPage']],
[4, ['success', 'SuccessPage']],
[5, ['cancel', 'CancelPage']],
['default', ['other', 'Index']],
])
const onButtonClick = (status) => {
let action = actions.get(status) || actions.get('default')
sendLog(action[0])
jumpTo(action[1])
}
Использование Карты вместо Объекта имеет много преимуществ.Между объектами Карты и обычными объектами есть следующие отличия:
- Объект обычно имеет свой собственный прототип, поэтому объект всегда имеет ключ «прототип».
- Ключ объекта может быть только строкой или символом, но ключ Карты может быть любым значением.
- Вы можете легко получить количество пар ключ-значение в Map, используя свойство size, в то время как количество пар ключ-значение в объекте не может быть получено напрямую.
Теперь давайте увеличим сложность этой проблемы. При нажатии кнопки необходимо судить не только о состоянии, но и о личности пользователя.
const onButtonClick = (status, identity) => {
if (identity == 'guest') {
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 (status == 5) {
//do sth
} else {
//do sth
}
} else if (identity == 'master') {
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 (status == 5) {
//do sth
} else {
//do sth
}
}
}
Как видно из приведенного выше примера, когда ваша логика обновляется до двойного суждения, ваше суждение удваивается, и ваш код удваивается.
Как сделать код чище?
Вот решение.
const actions = new Map([
['guest_1', () => {}],
['guest_2', () => {}],
['guest_3', () => {}],
['guest_4', () => {}],
['guest_5', () => {}],
['master_1', () => {}],
['master_2', () => {}],
['master_3', () => {}],
['master_4', () => {}],
['master_5', () => {}],
['default', () => {}],
])
const onButtonClick = (identity, status) => {
let action = actions.get(`${identity}_${status}`) || actions.get('default')
action.call(this)
}
Основная логика приведенного выше кода такова. Два условия оценки объединяются в строку в качестве ключа карты, а затем при запросе напрямую запрашивается значение соответствующей строки. Конечно, здесь мы также можем изменить карту на объект.
const actions = {
guest_1: () => {},
guest_2: () => {},
//....
}
const onButtonClick = (identity, status) => {
let action = actions[`${identity}_${status}`] || actions['default']
action.call(this)
}
Если читателю неудобно записывать запрос в виде строки, есть другое решение — использовать объект Map в качестве ключа.
const actions = new Map([
[{ identity: 'guest', status: 1 }, () => {}],
[{ identity: 'guest', status: 2 }, () => {}],
//...
])
const onButtonClick = (identity, status) => {
let action = [...actions].filter(([key, value]) => key.identity == identity && key.status == status)
action.forEach(([key, value]) => value.call(this))
}
Здесь вы также можете увидеть разницу между Картой и обычным объектом, где Карта может использовать любой тип данных в качестве ключа. Теперь давайте сделаем это немного сложнее. Что, если логика обработки для состояний 1-4 такая же, как и для гостевого удостоверения?
В худшем случае это (много дублирования кода):
const actions = new Map([
[{ identity: 'guest', status: 1 }, () => {}],
[{ identity: 'guest', status: 2 }, () => {}],
[{ identity: 'guest', status: 3 }, () => {}],
[{ identity: 'guest', status: 4 }, () => {}],
[{ identity: 'guest', status: 5 }, () => {}],
//...
])
Лучшим подходом является выделение функций логики обработки:
const actions = () => {
const functionA = () => {}
const functionB = () => {}
return 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 onButtonClick = (identity, status) => {
let action = [...actions()].filter(([key, value]) => key.identity == identity && key.status == status)
action.forEach(([key, value]) => value.call(this))
}
Этого достаточно для повседневных нужд, а если серьезно, то функция А упоминается 4 раза, что все равно немного раздражает.
Если все становится действительно сложным, например, 3 личности и 10 состояний, вам нужно определить 30 логик обработки, многие из которых одинаковы, что кажется неприемлемым.
И вы можете сделать это:
const actions = () => {
const functionA = () => {} // 逻辑处理 A
const functionB = () => {} // 逻辑处理 B
return new Map([
[/^guest_[1-4]$/, functionA],
[/^guest_5$/, functionB],
//...
])
}
const onButtonClick = (identity, status) => {
let action = [...actions()].filter(([key, value]) => key.test(`${identity}_${status}`))
action.forEach(([key, value]) => value.call(this))
}
Преимущество использования Map вместо Object очевидно, поскольку в качестве ключей можно использовать регулярные выражения.
Если требование становится таким: все гостевые операции должны отправлять точку логирования, а у гостей в разных состояниях может быть разная логическая обработка, то мы можем написать так:
const actions = () => {
const functionA = () => {} // 逻辑处理 A
const functionB = () => {} // 逻辑处理 B
const functionC = () => {} // 发送日志 C
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))
}
Таким образом, общая логика и индивидуальная логика могут выполняться одновременно.
Суммировать
В этой статье рассказывается о восьми способах написания логических суждений JS, в том числе:
- if/else
- switch
- Единое суждение: хранится в объекте
- Единое суждение: хранится в объекте MAP
- Множественные суждения: объединить условия в строку и сохранить в объекте
- Множественные суждения: объедините условия в строку и сохраните ее в объекте карты.
- Множественные суждения: сохраняйте условия как объекты на карте
- Множественные суждения: запишите условия в виде регулярных выражений и сохраните их в Map
Поделитесь этим здесь сегодня, пусть ваша будущая кодинговая жизнь будет больше, чем if/else или switch.