Easy way to understand nested ternary operators?

懵懂的女人 提交于 2019-12-14 02:42:09

问题


Is there a simple heuristic for understanding how to read nested ternary operators? I came across this in someone's source code and can't grok it. A simple ternary is easy:

isRed = color == 'red' ? true : false

But how do you read the following? Can I just line up the first with the last and the second with the second to last, or must I parse this into an if/else tree in my head?

var offset =
  ( hasFrozenRows )
    ? ( options.frozenBottom )
    ? ( row >= actualFrozenRow )
    ? ( h < viewportTopH )
    ? ( actualFrozenRow * options.rowHeight )
    : h
    : 0
    : ( row >= actualFrozenRow )
    ? frozenRowsHeight
    : 0
    : 0;

Retabbed, it can look like this, which is almost understandable (?)

      var offset =
        ( hasFrozenRows ) ?
          ( options frozenBottom ) ?
            ( row >= actualFrozenRow ) ?
              ( h < viewportTopH ) ?
                ( actualFrozenRow * options.rowHeight )
                :
                h
              :
              0
            :
            ( row >= actualFrozenRow ) ?
              frozenRowsHeight
              :
              0
            :
            0;

回答1:


I think you could have more luck if you try to read it as a series of check this, if true then this, else that.

For this, it might be easier to put the ? and : operators at the beginning of lines, and read them as if they were arrows on a flowchart, labeled "yes" and "no". e.g.:

cond1 
  ? cond2 
    ? cond3 
      ? res1 
      : res2
    : res3
  : res4

Which could be read as:

cond1?
  yes -> is cond2 
    yes -> is cond3?
      yes -> res1 
      no -> res2
    no -> res3
  no -> res4

That still doesn't make this very readable, and I agree with all the comments saying this kind of code should really be rewritten to be readable.




回答2:


For something messy like this you have to work from the outside in. Essentially, what this maps to is this:

if ( hasFrozenRows ) {
  if ( options.frozenBottom ) {
    if ( row >= actualFrozenRow ) {
      if ( h < viewportTopH ) {
        return ( actualFrozenRow * options.rowHeight )
      } else {
        return h;
      }
    } else {
      return 0;
    }
  } else {
    if ( row >= actualFrozenRow ) {
      return frozenRowsHeight
    } else {
      return 0
    }
  }
} else {
  return 0;
}

And I thought the legacy code I worked with was a nightmare...

I recommend running this through a unit tester, like Jasmine, and compare the outputs with the original code to confirm that it's the same.




回答3:


must I parse this into an if/else tree in my head?

Yes, because in this case it is a tree and not simply chained operators. Those would be easy to understand :-) Without indentation, this definitely needs refactoring.

In this particular case, it also would be helpful to negate the conditions, making reading a lot easier as it puts the condition and the effect directly next to each other:

var offset = (!hasFrozenRows)
               ? 0
               : (!options.frozenBottom)
                 ? (row < actualFrozenRow)
                   ? 0
                   : (h < viewportTopH)
                     ? actualFrozenRow * options.rowHeight
                     : h
                 : (row >= actualFrozenRow)
                   ? frozenRowsHeight
                   : 0;

We also could move the duplicate row >= actualFrozenRow comparison one level up:

var offset = (!hasFrozenRows)
             ? 0
             : (row < actualFrozenRow)
               ? 0
               : (!options.frozenBottom)
                 ? frozenRowsHeight
                 : (h < viewportTopH)
                   ? actualFrozenRow * options.rowHeight
                   : h;

…which actually renders it completely understandable, even if not negated:

var offset = ( hasFrozenRows )
             ? ( row >= actualFrozenRow )
               ? ( options.frozenBottom )
                 ? ( h < viewportTopH )
                   ? actualFrozenRow * options.rowHeight
                   : h
                 : frozenRowsHeight
               : 0
             : 0;

You now can also see that you might merge the first two conditions to hasFrozenRows && row >= actualFrozenRow.



来源:https://stackoverflow.com/questions/22997226/easy-way-to-understand-nested-ternary-operators

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!