SOURCE

console 命令行工具 X clear

                    
>
console
const testListWithNestedDicts = [
    {
        "studentId": 1,
        "age": 7,
        "height": 2,
        "weight": 3,
        "scores": {
            "spanish": 80,
            "mathematics": 90,
            "english": 100,
            "pe": {
                "run": 85,
                "jump": 95
            }
        }
    },
    {
        "studentId": 2,
        "age": 8,
        "height": 4,
        "weight": 6,
        "scores": {
            "spanish": 90,
            "mathematics": 90,
            "english": 80,
            "pe": {
                "run": 90,
                "jump": 90
            }
        }
    },
    {
        "studentId": 3,
        "age": 7,
        "height": 3,
        "weight": 6,
        "scores": {
            "spanish": 86,
            "mathematics": 90,
            "english": 75,
            "pe": {
                "run": 65,
                "jump": 90
            }
        }
    }
]

const propertys = [
    'age',
    'height',
    'weight',
    'scores',
    'spanish',
    'mathematics',
    'english',
    'pe',
    'run',
    'jump'
]

function calcAverage(arr, propertys) {
    const resultTotal = {}
    const resultCountProperty = {}

    //读取每一项进行解析
    for(let i = 0; i < arr.length; i++) {
        recursionObj(arr[i], resultTotal)
    }

    // 递归解析obj 算出总数和属性对应的数量
    function recursionObj(obj, targetObj = resultTotal) {
        for(let k in obj) {
            if (propertys.includes(k)) {
                if (typeof obj[k] === 'number') {
                    const countProperty = k
                    if (targetObj[k] === undefined) {
                        targetObj[k] = obj[k]
                        resultCountProperty[countProperty] = 1
                    } else {
                        targetObj[k] = accAdd(obj[k], targetObj[k]) //默认情况下值都是数字
                        resultCountProperty[countProperty] = resultCountProperty[countProperty] + 1
                    }
                } else if (Object.prototype.toString.call(obj[k]) === '[object Object]') {
                    targetObj[k] = targetObj[k] || {}
                    recursionObj(obj[k], targetObj[k])
                }
            }
        }
    }

    // 计算总数和数量的平均值
    function recursionResult(obj) {
        for (let k in obj) {
            if (Object.prototype.toString.call(obj[k]) === '[object Object]') {
                recursionResult(obj[k])
            } else {
                obj[k] = Math.round(accDiv(obj[k], resultCountProperty[k]) * 100) / 100 //不考虑负数的情况下四舍五入
            }
        }
    }
    recursionResult(resultTotal)

    //输出打印结果
    console.log(resultTotal)

    return resultTotal
}
const $code = document.getElementById('$code')
const result = calcAverage(testListWithNestedDicts, propertys)
$code.innerHTML = JSON.stringify(result)


/**
 ** 加法函数,用来得到精确的加法结果
 ** 说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。
 ** 调用:accAdd(arg1,arg2)
 ** 返回值:arg1加上arg2的精确结果
 **/
function accAdd(arg1, arg2) {
  let r1, r2, m
  try {
    r1 = arg1.toString().split('.')[1].length
  } catch (e) {
    r1 = 0
  }
  try {
    r2 = arg2.toString().split('.')[1].length
  } catch (e) {
    r2 = 0
  }
  m = Math.pow(10, Math.max(r1, r2))
  return (arg1 * m + arg2 * m) / m
}

/**
 ** 除法函数,用来得到精确的除法结果
 ** 说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。
 ** 调用:accDiv(arg1,arg2)
 ** 返回值:arg1除以arg2的精确结果
 **/
function accDiv(arg1, arg2) {
  let t1 = 0
  let t2 = 0
  let r1
  let r2
  try {
    t1 = arg1.toString().split('.')[1].length
  } catch (e) { }
  try {
    t2 = arg2.toString().split('.')[1].length
  } catch (e) { }
  r1 = Number(arg1.toString().replace('.', ''))
  r2 = Number(arg2.toString().replace('.', ''))
  return (r1 / r2) * Math.pow(10, t2 - t1)
}
<code id="$code">
    
</code>