嘗試獲取數組的平均值。爲什麼我的基於reduce的平均函數返回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
函數調用返回NaN
?
嘗試獲取數組的平均值。爲什麼我的基於reduce的平均函數返回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
函數調用返回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
時,需要考慮以下兩點。
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
。
您的匿名除了函數不返回任何值,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
。
無論從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
你已經有了答案,其他人提供你的問題,但我想我只是擴大用一個例子我的意見。
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>
從你的代碼中,人們會認爲你是針對一個現代瀏覽器。我建議使用Object.defineProperty來擴展Array.prototype。 (並且測試該方法不存在)。你甚至可以使代碼更加通用,與其他對象一起工作(調用/應用)。 – Xotic750 2015-02-08 09:45:20