为什么我的基于减少的平均函数返回NaN?

时间:2015-02-08 09:33:17

标签: javascript arrays math prototype

试图获得数组的平均值。

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

4 个答案:

答案 0 :(得分:10)

您的程序无效,因为a具有上一个函数调用的累计值。第一次,将使用数组的前两个值。因此sum将成为172 + 15)。由于您未从函数返回任何内容,因此默认情况下将返回undefined,并在下次调用中将其用作a的值。所以,评估就像这样

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

因此,sumNaN,因为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的函数中的第一个参数会累积结果并最终返回,使用它。无需使用单独的变量来跟踪结果。

  3. 所以你的代码看起来会像这样

    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将存储在{{1}}中。

答案 1 :(得分:6)

您的匿名添加函数不返回任何值,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再次给出{{1}}。

答案 2 :(得分:2)

您已经有了其他人提供的问题的答案,但我想我只是通过示例扩展我的评论。



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>
&#13;
&#13;
&#13;

答案 3 :(得分:1)

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

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

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

另请注意,减去第二个参数在对数字求和时非常有用,除非您尝试从零以外的数字求和,这并非完全对一组数字求和号。

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