为什么我基于 reduce 的平均函数 return NaN?

Why does my reduce based average function return NaN?

正在尝试获取数组的平均值。

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

[2, 15, 7].average();

为什么average函数调用returnNaN

您的匿名加法函数没有 return 任何值,reduce 适用于 return 值的函数:

尝试:

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.

您的程序无法运行,因为 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 中 return 得到什么值,它都会成为下一次调用的第一个参数,所以你必须 return 一些东西。此外,如果您有意扩展原型,请务必先检查是否存在,以免覆盖其他人的方法。

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

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

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

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>