Как мне обращаться с вложенными условными утверждениями? - PullRequest
0 голосов
/ 21 февраля 2019

У меня есть ряд вложенных условных проверок, и я пытаюсь найти чистое решение и максимально избежать ада if{}else{}.Пожалуйста, посмотрите пример кода как демонстрацию того, чего я пытаюсь достичь.

Итак, у меня есть два объекта, CACHE_FILE_AGE_LIMIT и CACHE_FILE_CURRENT_AGE, и я пытаюсь пройти проверку вложенного возраста:

first check the days,
    then check hours,
       then check minutes,
           then check seconds

Идея состоит в том, что, когда мы достигаем большего значения, например, дни равны, тогда мы переходим к часам, и если мы получаем там большее значение часа, мы заканчиваем проверку.

Для получения дополнительной информации см. Пример.

const CACHE_FILE_AGE_LIMIT = {
  days: 3,
  hours: 6,
  minutes: 15,
  seconds: 57
}

const CACHE_FILE_CURRENT_AGE = {
  days: 3,
  hours: 5,
  minutes: 14,
  seconds: 57
}

function timeDiff(ageObj1, ageObj2) {
  console.log('days_limit', ageObj1.days, '?', 'days_age', ageObj2.days);
  // old: days
  document.getElementById("current_days").innerHTML = ageObj2.days;
  if (ageObj1.days < ageObj2.days) {
    console.log('old (days)');
    document.getElementById("current_days").classList.add("red");
    return true;
  } else {
  	// equal: days
    if (ageObj1.days == ageObj2.days) {
    	document.getElementById("current_hours").innerHTML = ageObj2.hours;
      console.log('\tnext: hours');
      console.log('\thours_limit', ageObj1.hours, '?', 'hours_age', ageObj2.hours);
      if (ageObj1.hours < ageObj2.hours) {
        console.log('\told (hours)');
        document.getElementById("current_hours").classList.add("red");
        return true;
      } else {
        // equal: hours
        if (ageObj1.hours == ageObj2.hours) {
          document.getElementById("current_minutes").innerHTML = ageObj2.minutes;
          console.log('\t\tnext (minutes)');
          console.log('\t\tminutes_limit', ageObj1.minutes, '?', 'minutes_age', ageObj2.minutes);
          if (ageObj1.minutes < ageObj2.minutes) {
            // old: minutes
            console.log('\t\told (minutes)');
            document.getElementById("current_minutes").classList.add("red");
            return true;
          } else {
            // equal: minutes
            if (ageObj1.minutes == ageObj2.minutes) {
              document.getElementById("current_seconds").innerHTML = ageObj2.seconds;
              console.log('\t\t\tnext (seconds)');
              console.log('\t\t\tseconds_limit', ageObj1.seconds, '?', 'seconds_age', ageObj2.seconds);
              if (ageObj1.seconds < ageObj2.seconds) {
                console.log('\t\t\told (seconds)');
                document.getElementById("current_seconds").classList.add("red");
                return true;
              } else {
                console.log('\t\t\tNOT old (seconds)');
                document.getElementById("current_seconds").classList.add("blue");
                return false;
              }
            } else {
              console.log('\t\tNOT old (minutes)');
              return false;
            }
          }
        } else {
          console.log('\tNOT old (hours)');
          document.getElementById("current_hours").classList.add("blue");
          return false;
        }
      }
    } else {
      console.log('NOT old (days)');
      document.getElementById("current_days").classList.add("blue");
      return false;
    }
  }
}

// Populate Limits
var limit_fields = document.querySelectorAll(".limit");
for(i=0; i < limit_fields.length; i++){
				//console.log('--->', i)
        let id = limit_fields[i].id.split("_")[1];
        let val = CACHE_FILE_AGE_LIMIT[id]
        //console.log('\tid:', id, 'val:', val);
        limit_fields[i].innerHTML = val;
    }

// Evaluate Age
document.getElementById("output").innerHTML = timeDiff(CACHE_FILE_AGE_LIMIT, CACHE_FILE_CURRENT_AGE) ? "old" : "up to date";
.tg {
  border-collapse: collapse;
  border-spacing: 0;
}

.tg td {
  font-family: Arial, sans-serif;
  font-size: 12px;
  padding: 10px 5px;
  border-style: solid;
  border-width: 1px;
  overflow: hidden;
  word-break: normal;
  border-color: black;
}

.tg th {
  font-family: Arial, sans-serif;
  font-size: 12px;
  font-weight: normal;
  padding: 10px 5px;
  border-style: solid;
  border-width: 2px;
  overflow: hidden;
  border-color: black;
}

.tg .value {
  color: blue;
  text-align: center;
  vertical-align: top;
}

.tg .current {
  color: blue;
  text-align: center;
  vertical-align: top;
}

.tg .current.red {
  color: red;
}

.tg .current.blue {
  color: blue;
}

.tg .limit {
  color: #85929E;
  text-align: center;
  vertical-align: top;
}

.tg .header {
  background-color: #ffffc7;
  text-align: center;
  vertical-align: top;
}

.tg .item {
  background-color: #ffffc7;
  font-style: italic;
  text-align: right;
  vertical-align: top;
}

.tg .empty {
  background-color: #9b9b9b;
  text-align: right;
  vertical-align: top;
}

.tg .result {
  font-weight: bold;
  font-style: italic;
  background-color: #ffce93;
  text-align: right;
  vertical-align: top;
}

.tg .output {
  background-color: #FDEBD0;
  text-align: center;
  vertical-align: top;
}
<table class="tg" style="undefined;table-layout: fixed; width: 265px">
  <colgroup>
    <col style="width: 92px">
    <col style="width: 92px">
    <col style="width: 92px">
  </colgroup>
  <tr>
    <th class="empty"></th>
    <th class="header">CURRENT</th>
    <th class="header">LIMITS</th>
  </tr>
  <tr>
    <td class="item">DAYS</td>
    <td id="current_days" class="value current">-</td>
    <td id="limit_days" class="value limit"></td>
  </tr>
  <tr>
    <td class="item">HOURS</td>
    <td id="current_hours" class="value current">-</td>
    <td id="limit_hours" class="value limit"></td>
  </tr>
  <tr>
    <td class="item">MINUTES</td>
    <td id="current_minutes" class="value current">-</td>
    <td id="limit_minutes" class="value limit"></td>
  </tr>
  <tr>
    <td class="item">SECONDS</td>
    <td id="current_seconds" class="value current">-</td>
    <td id="limit_seconds" class="value limit"></td>
  </tr>
  <tr>
    <td class="result">RESULT</td>
    <td id="output" class="output" colspan="2">up to date</td>
  </tr>
</table>

Итак, как вы можете видеть, условное выполнение заканчивается, когда становится ясно, что hours достаточно для определения возраста.

Пожалуйста, измените значения в CACHE_FILE_CURRENT_AGE, чтобы проверить его.

--- ОБНОВЛЕНИЕ ---

Было несколько решений, поэтому всем спасибо за помощь.К сожалению, мне придется выбрать один из ответов, чтобы закрыть вопрос.

Вот демонстрация решения:

enter image description here

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Таким образом, другая возможность - создать что-то вроде массива UNITS, который содержит просто текстовое представление каждого свойства вашего объекта time-ish в том порядке, в котором вы хотите их обработать.Затем просто используйте цикл while для итерации по этому массиву UNITS и обновляйте каждый элемент DOM по очереди.

const CACHE_FILE_AGE_LIMIT = {
  days: 3,
  hours: 6,
  minutes: 15,
  seconds: 57
}, CACHE_FILE_CURRENT_AGE = {
  days: 3,
  hours: 5,
  minutes: 17, 
  seconds: 57
  
}, UNITS = ["days", "hours","minutes","seconds"]

function timeDiff(ageObj1, ageObj2) {
  // We create a flag, and an index to iterate over our UNITS array
  let unitsIndex = 0;
  
  // if the upToDate flag is TRUE
  while(unitsIndex <= UNITS.length){
    // We'll use template literals to create the IDs
    currentEl = document.getElementById(`current_${UNITS[unitsIndex]}`),
    limitEl = document.getElementById(`limit_${UNITS[unitsIndex]}`);

    console.log(UNITS[unitsIndex],ageObj1[UNITS[unitsIndex]],ageObj2[UNITS[unitsIndex]]) 
    // Update the content of the current and limit elements    
    currentEl.innerHTML = ageObj2[UNITS[unitsIndex]];
    limitEl.innerHTML = ageObj1[UNITS[unitsIndex]];
    
    // Here we check: is our limit unit less than our current?
    if (ageObj1[UNITS[unitsIndex]] < ageObj2[UNITS[unitsIndex]]) {
      /**
       * In this case, our current has exceeded our limit. Bad bad bad.
       **/
       console.info(`The current ${UNITS[unitsIndex]} is stale.`)
      currentEl.classList.add("red");  
      return false;
    } else if(ageObj1[UNITS[unitsIndex]] > ageObj2[UNITS[unitsIndex]]){
      /**
       * In this case, our limit is  more than a full unit greater than our current. goodgoodgood.
       **/
       console.info(`The current ${UNITS[unitsIndex]} is more than a full unit to the good.`)
      return true;
    }
         
    //increment our UNITS array pointer
    unitsIndex++;
  }
  // if we get here, then all the DHMS have passed --  we can return true
  return true;
}

// Populate Limits
var limit_fields = document.querySelectorAll(".limit");
for(i=0; i < limit_fields.length; i++){
				//console.log('--->', i)
        let id = limit_fields[i].id.split("_")[1];
        let val = CACHE_FILE_AGE_LIMIT[id]
        //console.log('\tid:', id, 'val:', val);
        limit_fields[i].innerHTML = val;
    }

// Evaluate Age
document.getElementById("output").innerHTML = timeDiff(CACHE_FILE_AGE_LIMIT, CACHE_FILE_CURRENT_AGE) ? "up to date" : "old";
.tg {
  border-collapse: collapse;
  border-spacing: 0;
}

.tg td {
  font-family: Arial, sans-serif;
  font-size: 12px;
  padding: 10px 5px;
  border-style: solid;
  border-width: 1px;
  overflow: hidden;
  word-break: normal;
  border-color: black;
}

.tg th {
  font-family: Arial, sans-serif;
  font-size: 12px;
  font-weight: normal;
  padding: 10px 5px;
  border-style: solid;
  border-width: 2px;
  overflow: hidden;
  border-color: black;
}

.tg .value {
  color: blue;
  text-align: center;
  vertical-align: top;
}

.tg .current {
  color: blue;
  text-align: center;
  vertical-align: top;
}

.tg .current.red {
  color: red;
}

.tg .current.blue {
  color: blue;
}

.tg .limit {
  color: #85929E;
  text-align: center;
  vertical-align: top;
}

.tg .header {
  background-color: #ffffc7;
  text-align: center;
  vertical-align: top;
}

.tg .item {
  background-color: #ffffc7;
  font-style: italic;
  text-align: right;
  vertical-align: top;
}

.tg .empty {
  background-color: #9b9b9b;
  text-align: right;
  vertical-align: top;
}

.tg .result {
  font-weight: bold;
  font-style: italic;
  background-color: #ffce93;
  text-align: right;
  vertical-align: top;
}

.tg .output {
  background-color: #FDEBD0;
  text-align: center;
  vertical-align: top;
}
<table class="tg" style="undefined;table-layout: fixed; width: 265px">
  <colgroup>
    <col style="width: 92px">
    <col style="width: 92px">
    <col style="width: 92px">
  </colgroup>
  <tr>
    <th class="empty"></th>
    <th class="header">CURRENT</th>
    <th class="header">LIMITS</th>
  </tr>
  <tr>
    <td class="item">DAYS</td>
    <td id="current_days" class="value current">-</td>
    <td id="limit_days" class="value limit"></td>
  </tr>
  <tr>
    <td class="item">HOURS</td>
    <td id="current_hours" class="value current">-</td>
    <td id="limit_hours" class="value limit"></td>
  </tr>
  <tr>
    <td class="item">MINUTES</td>
    <td id="current_minutes" class="value current">-</td>
    <td id="limit_minutes" class="value limit"></td>
  </tr>
  <tr>
    <td class="item">SECONDS</td>
    <td id="current_seconds" class="value current">-</td>
    <td id="limit_seconds" class="value limit"></td>
  </tr>
  <tr>
    <td class="result">RESULT</td>
    <td id="output" class="output" colspan="2">up to date</td>
  </tr>
</table>

Обратите внимание, что я использую литералы Template для определения идентификатора на каждой итерации:

`current_${UNITS[unitIndex] }`

By doing so, I don't have to hard-code the id every time. As long as I can trust the prefixes, this works pretty well. And it seems to get rid of a lot of your if statements, simply by running them each sequentially.

EDIT: I'm an idiot. So there are two branches to your if statement (well, three). First, if the current is beyond the limit, return false immediately, as that is OLD. Second, if the limit is more than a full unit greater than the current, immediately return true, as the current is well within its limit. Third, if they are equal, loop on to the next unit. If all units process and we fall through the while loop, then  they are the same exact. Weird, but still good. Code updated to reflect the SECOND case.
0 голосов
/ 21 февраля 2019

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

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

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

const CACHE_FILE_AGE_LIMIT = {
  days: 3,
  hours: 6,
  minutes: 15,
  seconds: 57
}

const CACHE_FILE_CURRENT_AGE = {
  days: 3,
  hours: 5,
  minutes: 14,
  seconds: 57
}

function timeDiff(ageObj1, ageObj2) {
    var flag;
    [
        () => {
            document.getElementById("current_days").innerHTML = ageObj2.days;
            if (ageObj1.days < ageObj2.days) {
                document.getElementById("current_days").classList.add("red");
                return flag = true;
            }
        },
        () => {
            if (ageObj1.days == ageObj2.days) {
                document.getElementById("current_hours").innerHTML = ageObj2.hours;
            } else {
                document.getElementById("current_days").classList.add("blue");
                flag = false;
                return true;
            }
        },
        () => {
            if (ageObj1.hours < ageObj2.hours) {
                document.getElementById("current_hours").classList.add("red");
                return flag = true;
            }
        },
        () => {
            if (ageObj1.hours == ageObj2.hours) {
                document.getElementById("current_minutes").innerHTML = ageObj2.minutes;
            } else {
                document.getElementById("current_hours").classList.add("blue");
                flag = false;
                return true;
            }
        },
        () => {
            if (ageObj1.minutes < ageObj2.minutes) {
                document.getElementById("current_minutes").classList.add("red");
                return flag = true;
            }
        },
        () => {
            if (ageObj1.minutes == ageObj2.minutes) {
                document.getElementById("current_seconds").innerHTML = ageObj2.seconds;
            } else {
                flag = false;
                return true;
            }
        },
        () => {
            if (ageObj1.seconds < ageObj2.seconds) {
                document.getElementById("current_seconds").classList.add("red");
                return flag = true;
            } else {
                document.getElementById("current_seconds").classList.add("blue");
                flag = false;
                return true;
            }
        }
    ].some(fn => fn());
    return flag;
}


// Populate Limits
var limit_fields = document.querySelectorAll(".limit");
for(i=0; i < limit_fields.length; i++){
				//console.log('--->', i)
        let id = limit_fields[i].id.split("_")[1];
        let val = CACHE_FILE_AGE_LIMIT[id]
        //console.log('\tid:', id, 'val:', val);
        limit_fields[i].innerHTML = val;
    }

// Evaluate Age
document.getElementById("output").innerHTML = timeDiff(CACHE_FILE_AGE_LIMIT, CACHE_FILE_CURRENT_AGE) ? "old" : "up to date";
.tg {
  border-collapse: collapse;
  border-spacing: 0;
}

.tg td {
  font-family: Arial, sans-serif;
  font-size: 12px;
  padding: 10px 5px;
  border-style: solid;
  border-width: 1px;
  overflow: hidden;
  word-break: normal;
  border-color: black;
}

.tg th {
  font-family: Arial, sans-serif;
  font-size: 12px;
  font-weight: normal;
  padding: 10px 5px;
  border-style: solid;
  border-width: 2px;
  overflow: hidden;
  border-color: black;
}

.tg .value {
  color: blue;
  text-align: center;
  vertical-align: top;
}

.tg .current {
  color: blue;
  text-align: center;
  vertical-align: top;
}

.tg .current.red {
  color: red;
}

.tg .current.blue {
  color: blue;
}

.tg .limit {
  color: #85929E;
  text-align: center;
  vertical-align: top;
}

.tg .header {
  background-color: #ffffc7;
  text-align: center;
  vertical-align: top;
}

.tg .item {
  background-color: #ffffc7;
  font-style: italic;
  text-align: right;
  vertical-align: top;
}

.tg .empty {
  background-color: #9b9b9b;
  text-align: right;
  vertical-align: top;
}

.tg .result {
  font-weight: bold;
  font-style: italic;
  background-color: #ffce93;
  text-align: right;
  vertical-align: top;
}

.tg .output {
  background-color: #FDEBD0;
  text-align: center;
  vertical-align: top;
}
<table class="tg" style="undefined;table-layout: fixed; width: 265px">
  <colgroup>
    <col style="width: 92px">
    <col style="width: 92px">
    <col style="width: 92px">
  </colgroup>
  <tr>
    <th class="empty"></th>
    <th class="header">CURRENT</th>
    <th class="header">LIMITS</th>
  </tr>
  <tr>
    <td class="item">DAYS</td>
    <td id="current_days" class="value current">-</td>
    <td id="limit_days" class="value limit"></td>
  </tr>
  <tr>
    <td class="item">HOURS</td>
    <td id="current_hours" class="value current">-</td>
    <td id="limit_hours" class="value limit"></td>
  </tr>
  <tr>
    <td class="item">MINUTES</td>
    <td id="current_minutes" class="value current">-</td>
    <td id="limit_minutes" class="value limit"></td>
  </tr>
  <tr>
    <td class="item">SECONDS</td>
    <td id="current_seconds" class="value current">-</td>
    <td id="limit_seconds" class="value limit"></td>
  </tr>
  <tr>
    <td class="result">RESULT</td>
    <td id="output" class="output" colspan="2">up to date</td>
  </tr>
</table>

Но вы можете взять массив с ключами и выполнять до тех пор, пока некоторые части не вернутся true.

function timeDiff(ageObj1, ageObj2) {
    var flag;

    ['days', 'hours', 'minutes', 'seconds'].some((key, index, keys) => {
        var nextKey = keys[index + 1],
            element = document.getElementById("current_" + key),
            nextElement = document.getElementById("current_" + nextKey);

        element.innerHTML = ageObj2[key];
        if (ageObj1[key] < ageObj2[key]) {
            element.classList.add("red");
            return flag = true;
        }
        if (ageObj1[key] == ageObj2[key] && nextKey) {
            nextElement.innerHTML = ageObj2[nextKey];
        } else {
            element.classList.add("blue");
            flag = false;
            return true;
        }
    });

    return flag;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...