当前位置: 首页 > 知识库问答 >
问题:

如何重构这一功能,将其认知复杂度从17降低到允许的15

吴均
2023-03-14

>

  • 如何重构该函数以减少复杂度
  • 当我使用开关大小写时,代码的兼容性更高,那么如何减少它

    如何实现此功能

    
    var has = Object.prototype.hasOwnProperty
    
    
    
    var toString = Object.prototype.toString
    
    
    function isEmpty(val) {
     
      if (val == null) return true
      if ('boolean' == typeof val) return false
      if ('number' == typeof val) return val === 0
      if ('string' == typeof val) return val.length === 0
      if ('function' == typeof val) return val.length === 0
      if (Array.isArray(val)) return val.length === 0
      if (val instanceof Error) return val.message === ''
      if (val.toString == toString) {
        switch (val.toString()) {
          case '[object File]':
          case '[object Map]':
          case '[object Set]': {
            return val.size === 0
          }
          case '[object Object]': {
            for (var key in val) {
              if (has.call(val, key)) return false
            }
    
            return true
          }
        }
      }
      return false
    }
    module.exports = isEmpty
    
  • 共有1个答案

    濮阳钟展
    2023-03-14

    我最近给出了一个非常相似的问题的答案,更详细地介绍了认知复杂性是如何工作的(参见https://stackoverflow.com/a/62867219/7730554)。

    但总的来说,我认为重要的是要理解,如果有嵌套条件,认知复杂性会增加得更多。这种计算是这样做的,因为人脑可以更好地处理按顺序编写的语句,而不是嵌套的条件。因此,对于每个条件语句(if、switch、for循环等),复杂性值将增加+1。但是对于每一个嵌套条件,在最后一个级别上添加另一个+1。这意味着,if中的if不仅会加+1,还会加+2。一个if,在if里面,在if里面,结果第一个if是+1,第二个if是+2,第三个if是+3。如果您想深入研究这个问题,我建议您看看:https://www.sonarsource.com/docs/cognitiveComplexity.pdf

    因此,让我们首先分析方法中的高复杂度值来自哪里:

    function isEmpty(val) {
        if (val == null) return true // +1 
        if ('boolean' == typeof val) return false // +1
        if ('number' == typeof val) return val === 0 // +1
        if ('string' == typeof val) return val.length === 0 // +1
        if ('function' == typeof val) return val.length === 0 // +1
        if (Array.isArray(val)) return val.length === 0 // +1
        if (val instanceof Error) return val.message === '' // +1
        if (val.toString == toString) { // +1
            switch (val.toString()) { // +2
                case '[object File]':
                case '[object Map]':
                case '[object Set]': {
                    return val.size === 0
                }
                case '[object Object]': {
                    for (var key in val) { // +3
                        if (has.call(val, key)) return false // +4
                    }
    
                    return true
                }
            }
        }
        return false
    }
    
    function isEmpty(val) {
        if (val == null) return true // +1 
        if ('boolean' == typeof val) return false // +1
        if ('number' == typeof val) return val === 0 // +1
        if ('string' == typeof val) return val.length === 0 // +1
        if ('function' == typeof val) return val.length === 0 // +1
        if (Array.isArray(val)) return val.length === 0 // +1
        if (val instanceof Error) return val.message === '' // +1
        if (val.toString != toString) { // +1
            return false;
        }
        
        switch (val.toString()) { // +1
            case '[object File]':
            case '[object Map]':
            case '[object Set]': {
                return val.size === 0
            }
            case '[object Object]': {
                for (var key in val) { // +2
                    if (has.call(val, key)) return false // +3
                }
                return true
            }
        }
    }  
    

    现在,最后一个switch语句可以在if语句之外执行,我们将嵌套级别减少了一个。通过这个简单的改变,认知复杂度现在从17降到了14。

    然后,您甚至可以更进一步,通过将返回值提取到一个变量中来更改最后一个case语句,或者从代码块中提取一个单独的方法。这将进一步降低isEmpty()方法的复杂性。

    除了提取方法之外,您还可以使用声明性方法,例如数组方法find(),这将进一步降低认知复杂性。

    function isEmpty(val) {
        if (val == null) return true // +1 
        if ('boolean' == typeof val) return false // +1
        if ('number' == typeof val) return val === 0 // +1
        if ('string' == typeof val) return val.length === 0 // +1
        if ('function' == typeof val) return val.length === 0 // +1
        if (Array.isArray(val)) return val.length === 0 // +1
        if (val instanceof Error) return val.message === '' // +1
        if (val.toString != toString) { // +1
            return false;
        }
        
        return checkForComplexTypes(val)
    }
    
    function checkForComplexTypes(val) {
        var result = null
        switch (val.toString()) { // +1
            case '[object File]':
            case '[object Map]':
            case '[object Set]': {
                result = val.size === 0
            }
            case '[object Object]': {
                result = Object.keys(val).find(key => has.call(val, key))
            }
            return result
        }
    }
    
     类似资料: