2015-02-08 11 views
5

Próba uzyskania średniej z tablicy.Dlaczego moja średnia funkcja oparta na redukcji zwraca wartość NaN?

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

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

Dlaczego average funkcja oddzwaniania NaN?

+1

z kodu, można by zakładać, są kierowane nowoczesną przeglądarkę. Sugerowałbym użycie 'Object.defineProperty' do rozszerzenia' Array.prototype'. (i testowanie, że metoda nie istnieje w pierwszej kolejności). Można nawet uczynić kod bardziej ogólnym, aby działał '' (wywoływać/aplikuj) 'z innymi obiektami. – Xotic750

Odpowiedz

10

Twój program nie działa, ponieważ a ma skumulowaną wartość z poprzedniego wywołania funkcji. Za pierwszym razem zostaną użyte pierwsze dwie wartości tablicy. Tak więc sum stanie się 17 (2 + 15). Ponieważ nie zwracasz niczego z funkcji, domyślnie zostanie zwrócony kod undefined, który zostanie użyty jako wartość dla a w następnym wywołaniu. Tak więc ocena idzie tak

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

So, sum będzie miał NaN, ponieważ undefined + 7 sprawia, że ​​tak. Każda operacja numeryczna na NaN, zawsze da NaN, dlatego NaN/this.length, daje NaN. Możesz naprawić swój program, zwracając bieżącą wartość sum za każdym razem, gdy wywoływana jest funkcja, dzięki czemu przy następnym wywołaniu funkcji, a będzie miała odpowiednią skumulowaną wartość.

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

Ale nie wykorzystujemy tutaj mocy i elastyczności reduce. Oto dwa ważne punkty, które należy rozważyć podczas korzystania z reduce.

  1. akceptuje drugi parametr, który zawiera wartość początkową, która ma być użyta. O ile to możliwe, określ to.

  2. Pierwszy parametr w funkcji przekazanej do reduce kumuluje wynik, który zostanie ostatecznie zwrócony, skorzystaj z tego. Nie musisz używać oddzielnej zmiennej, aby śledzić wyniki.

Tak Twój kod będzie wyglądać lepiej jak ten

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 faktycznie działa w ten sposób. Wykonuje iterację w tablicy i przekazuje bieżącą wartość jako drugi parametr funkcji, a bieżący zakumulowany wynik jako pierwszy parametr, a wartość zwrócona z funkcji zostanie zapisana w skumulowanej wartości.Więc, suma jest rzeczywiście znalazł się ten

result: 0 , currentValue: 2 => 2 (Initializer value `0`) 
result: 2 , currentValue: 15 => 17 
result: 17, currentValue: 7 => 24 

Ponieważ zabrakło wartości z tablicy, 24 zostanie zwrócona jako wynik reduce, które będą przechowywane w sum.

6

Twoja anonimowa funkcja dodatek nie zwraca żadnej wartości, reduce współpracuje z funkcjami, które zwracają wartość:

Spróbuj:

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

Inną możliwością jest to, że tablica zawiera ciągi zamiast liczb, co cię może chcieć przymusić je do numerów za pomocą return (+a) + (+b); tak jakbyś miał "10.0" i "20.0", dodanie ich razem daje "10.020.0", który podzielony przez dowolną liczbę ponownie daje NaN.

1

Bez względu na to, jaka wartość jest zwracana przez redukuj, staje się ona pierwszym parametrem w następnym wywołaniu, więc musisz coś zwrócić. Także jeśli celowo przedłużacie prototypy, najpierw sprawdźcie istnienie, aby nie przesłonić metody innej osoby.

Nie ma potrzeby tworzenia żadnych innych zmiennych w treści funkcji, ponieważ wszystkie mogą być zaimplementowane w jednym wierszu.

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

Należy również pamiętać, że drugi parametr zmniejszyć nie jest bardzo przydatne, gdy zsumowanie cyfr, chyba że starasz się podsumować od szeregu innych niż zero, co nie jest dokładnie podsumowującej zestaw liczb.

Jest więcej informacji na MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

2

Masz już odpowiedź na swoje pytanie dostarczonych przez innych, ale myślałem, że po prostu rozwinąć mój komentarz z przykładu.

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>

Powiązane problemy