为什么我的基于约简的平均值函数返回 NaN

Why does my reduce based average function return NaN?

本文关键字:函数 返回 NaN 平均值 我的 于约简 为什么      更新时间:2023-09-26

试图获取数组的平均值。

Array.prototype.average = function() {
    var sum = 0;
    this.reduce(function(a, b) {
        sum = a + b;
    });
    return sum / this.length;
};
[2, 15, 7].average();

为什么average函数调用返回NaN

您的程序不起作用,因为a具有上一个函数调用的累积值。第一次,将使用数组的前两个值。所以sum会变得17(2 + 15(。由于您没有从函数返回任何内容,因此默认情况下将返回undefined,并且在下一次调用中将用作 a 的值。所以,评估是这样的

a: 2,          b: 15   => 17
a: undefined,  b: 7    => NaN

所以,sum会有NaN,因为undefined + 7使它如此。NaN上的任何数值运算,总是会给出NaN,这就是为什么NaN / this.length,给你NaN。你可以修复你的程序,只需在调用函数时返回当前值sum,以便在下一次函数调用时,a将具有适当的累积值。

Array.prototype.average = function() {
    var sum = 0;
    this.reduce(function(a, b) {
        sum = a + b;
        return sum;
    });
    return sum / this.length;
};

但是,我们在这里没有利用reduce的力量和灵活性。以下是使用reduce时要考虑的两个要点。

  1. reduce接受第二个参数,该参数表示要使用的初始值。尽可能指定。

  2. 传递给 reduce 的函数中的第一个参数累积结果,最终将返回,利用该参数。无需使用单独的变量来跟踪结果。

所以你的代码看起来会更好,这样

Array.prototype.average = function() {
    var sum = this.reduce(function(result, currentValue) {
        return result + currentValue
    }, 0);
    return sum / this.length;
};
console.log([2, 15, 7].average());
# 8

reduce实际上是这样工作的。它遍历数组并将当前值作为第二个参数传递给函数,将当前累积结果作为第一个参数传递给函数,从函数返回的值将存储在累积值中。所以,总和实际上是这样找到的

result: 0 , currentValue: 2   => 2    (Initializer value `0`)
result: 2 , currentValue: 15  => 17
result: 17, currentValue: 7   => 24

由于数组中的值用完了,24 将作为reduce的结果返回,该结果将存储在 sum 中。

您的匿名加法函数不返回任何值,reduce处理返回值的函数:

尝试:

Array.prototype.average = function() {
    var sum = this.reduce(function (a, b) {
        return a + b;
    }, 0);
    return sum/this.length;
};

另一种可能性是你的数组包含字符串而不是数字,因此你可能想用return (+a) + (+b)强迫它们为数字;就像你有"10.0""20.0"一样,将它们加在一起得到"10.020.0",再次除以任何数字得到NaN

您已经有了其他人提供的问题的答案,但我想我只是用一个例子来扩展我的评论。

if (!Array.prototype.average) {
    Object.defineProperty(Array.prototype, 'average', {
        value: function () {
            if (typeof this === 'undefined' || this === null) {
                throw new TypeError('Cannot convert argument to object');
            }
            var object = Object(this);
            return [].reduce.call(object, function (result, currentValue) {
                return +(currentValue) + result;
            }, 0) / object.length;
        }
    });
}
var out = document.getElementById('out');
out.textContent += [2, 15, 7].average() + ''n';
out.textContent += [].average.call({
    0: '2',
    1: '15',
    2: '7',
    length: 3
}) + ''n';
out.textContent += [].average.call('123') + ''n';
<pre id="out"></pre>

无论从reduce返回什么值,它都会成为下一次调用中的第一个参数,因此您必须返回一些内容。此外,如果您有意扩展原型,请确保首先检查是否存在,这样您就不会覆盖其他人的方法。

无需

在函数体中创建任何其他变量,因为它都可以在一行中实现。

if(!Array.prototype.average) {
  Array.prototype.average = function() {
    return this.reduce(function(a, b){ return a + b; }) / this.length;
  };
}

另请注意,reduce的第二个参数在对数字求和时不是很有用,除非您尝试从零以外的数字求和,而零并不完全对一组数字求和。

还有更多关于MDN的信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce