我怎么能减少圈复杂度?

Rol*_*and 15 javascript cyclomatic-complexity jshint

每当我拿出一段我正在处理的代码时,我就得到了This function's cyclomatic complexity is too high. (7).但我对如何以这种方式重写它有点困惑,所以它的工作原理.

这将是不断抛出该消息的函数:

function () {
  var duration = +new Date() - start.time,
    isPastHalf = Number(duration) < 250 && Math.abs(delta.x) > 20 || Math.abs(delta.x) > viewport / 2,
    direction = delta.x < 0;

  if (!isScrolling) {
    if (isPastHalf) {
      if (direction) {
        this.close();
      } else {
        if (this.content.getBoundingClientRect().left > viewport / 2 && pulled === true) {
          this.close();
          return;
        }
        this.open();
      }
    } else {
      if (this.content.getBoundingClientRect().left > viewport / 2) {
        if (this.isEmpty(delta) || delta.x > 0) {
          this.close();
          return;
        }
        this.open();
        return;
      }
      this.close();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我想听听一些关于如何以这种方式构建代码的建议,以避免这种情况.

Ber*_*rgi 24

那么你的代码中只有两个动作,但条件太多了.在条件中使用单个if-else语句和布尔运算符.如果这是不可能的,你至少可以

  • 删除空行以在一个屏幕页面上获取完整逻辑
  • 添加一些关于分支机构正在做什么的评论(以及为什么)
  • 避免早退

这是你的功能简化:

var duration = +new Date() - start.time,
    isPastHalf = Number(duration) < 250 && Math.abs(delta.x) > 20 || Math.abs(delta.x) > viewport / 2,
    isFarRight = this.content.getBoundingClientRect().left > viewport / 2, 
    direction = delta.x < 0;

if (!isScrolling) {
    if (isPastHalf) {
        if (direction)
            this.close();
        else {
            if (isFarRight && pulled)
                this.close();
            else
                this.open();
        }
    } else {
        if (isFarRight) {
            // Looks like the opposite of `direction`, is it?
            if (this.isEmpty(delta) || delta.x > 0)
                this.close();
            else
                this.open();
        } else
            this.close();
    }
}
Run Code Online (Sandbox Code Playgroud)

并缩短:

var duration = +new Date() - start.time,
    isPastHalf = Number(duration) < 250 && Math.abs(delta.x) > 20 || Math.abs(delta.x) > viewport / 2,
    isFarRight = this.content.getBoundingClientRect().left > viewport / 2, 
    direction = delta.x < 0,
    undirection = this.isEmpty(delta) || delta.x > 0;

if (!isScrolling) {
    if ( isPastHalf && !  direction && !(isFarRight && pulled)
     || !isPastHalf && !undirection &&  isFarRight )
        this.open();
    else
        this.close();
}
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,如果你试图尽量减少布尔数学,欺骗和使用[wolframalpha](http://www.wolframalpha.com/input/?i=%28a+%26%26+ !+b+%26%26 +!%28C +%26%26 + d%29 + || +!一个+%26%26 +!E +%26%26 + C%29) (2认同)
  • 甚至可以在分配之前完成警告返回.而且,if对我来说太复杂了.我将介绍另外两个变量来揭示isPastHalf &&!direction &&!(isFarRight && pull)和!isPastHalf && direction && isFarRight的实际含义. (2认同)

Dav*_*ani 5

首先,你的函数可以有三个结果:什么都不做,调用this.close()或调用this.open()。所以理想情况下,结果函数只有一个 if 语句来确定使用哪个结果。

下一步是将所有布尔代码提取到变量中。例如var leftPastCenter = this.content.getBoundingClientRect().left > viewport / 2

最后,使用布尔逻辑一步一步地简化它。

这是我如何做到的:

首先,提取所有布尔变量:

function () {
    var duration = +new Date() - start.time,
      isPastHalf = Number(duration) < 250 && Math.abs(delta.x) > 20 || Math.abs(delta.x) > viewport / 2,
      direction = delta.x < 0,
      leftPastCenter = this.content.getBoundingClientRect().left > viewport / 2,
      positiveDelta = this.isEmpty(delta) || delta.x > 0,
      isPulled = pulled === true; // I'll assume the test is needed rather than just using pulled.

    if (!isScrolling) {
        if (isPastHalf) {
            if (direction) {
                this.close();
            } else {
                if (leftPastCenter && isPulled) {
                    this.close();
                    return;
                }
                this.open();
            }
        } else {
            if (leftPastCenter) {
                if (positiveDelta) {
                    this.close();
                    return;
                }
                this.open();
                return;
            }
            this.close();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最容易退出的部分是意识到如果isScrolling是真的,什么都不会发生。这立即摆脱了一层嵌套:

    // above same
    if (isScrolling) { return; }

    if (isPastHalf) {
        if (direction) {
            this.close();
        } else {
            if (leftPastCenter && isPulled) {
                this.close();
                return;
            }
            this.open();
        }
    } else {
        if (leftPastCenter) {
            if (positiveDelta) {
                this.close();
                return;
            }
            this.open();
            return;
        }
        this.close();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在来看一下this.open()被调用的情况。如果isPastHalf为真,this.open()则仅在!direction和时调用!(leftPastCenter && isPulled)。如果isPastHalf为假,则this.open()仅在leftPastCenter和时调用!positiveDelta

    // above same
    if (isScrolling) { return; }

    if (isPastHalf) {
        if (!direction && !(leftPastCenter && isPulled)) {
            this.open();
        } else {
            this.close();
        }
    } else {
        if (leftPastCenter && !positiveDelta) {
            this.open();
        } else {
            this.close();
        }
    }
Run Code Online (Sandbox Code Playgroud)

翻转 ifs(所以this.close()先来),使代码更整洁,并给出我的最终版本:

    function () {

    var duration = +new Date() - start.time,
      isPastHalf = Number(duration) < 250 && Math.abs(delta.x) > 20 || Math.abs(delta.x) > viewport / 2,
      direction = delta.x < 0,
      leftPastCenter = this.content.getBoundingClientRect().left > viewport / 2,
      positiveDelta = this.isEmpty(delta) || delta.x > 0,
      isPulled = pulled === true; // I'll assume the test is needed rather than just using pulled.

    if (isScrolling) { return; }

    if (isPastHalf) {
        if (direction || (leftPastCenter && isPulled)) {
            this.close();
        } else {
            this.open();
        }
    } else {
        if (!leftPastCenter || positiveDelta) {
            this.close();
        } else {
            this.open();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在不了解您的代码库的情况下,我很难做更多事情。需要注意的一件事是direction,我的新变量positiveDelta几乎相同 - 您可以删除positiveDelta并仅使用direction. 此外,direction对于布尔值来说,这不是一个好名字,像movingLeft这样的名字会更好。