2015-02-08 453 views
5

嘗試獲取數組的平均值。爲什麼我的基於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

+1

從你的代碼中,人們會認爲你是針對一個現代瀏覽器。我建議使用Object.defineProperty來擴展Array.prototype。 (並且測試該方法不存在)。你甚至可以使代碼更加通用,與其他對象一起工作(調用/應用)。 – Xotic750 2015-02-08 09:45:20

回答

10

你的程序不起作用,因爲a具有前一個函數調用的累積值。第一次,數組的前兩個值將被使用。所以sum將變成172 + 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

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

無論從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

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>

相關問題