试图获得数组的平均值。
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
?
答案 0 :(得分:10)
您的程序无效,因为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
时需要考虑以下两点。
reduce
接受第二个参数,该参数表示要使用的初始值。只要有可能,请指定。
传递给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
将存储在{{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;
答案 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