2017-04-02 678 views
0

我想寫一個函數,它接受一個數組作爲輸入。如果整數是正數,則對其進行計數。如果整數是負數,則它將它相加。reduce()的第一個參數爲什麼返回undefined?

我覺得在js中的reduce()助手應該是最好的方式去做這件事,但是當我運行的時候,我會一直返回未定義的第一個參數。

這裏是我的代碼:

function countPositivesSumNegatives(input) { 
    let countPositive = 0; 
    let sumNegative = 0 

    if (input === null || input === []){ 
     return []; 
    } else { 
     return input.reduce(function(prev,num){ 
     if (num > 0) { 
     countPositive++; 
     }else{ 
     sumNegative = prev + num}; 
     }, 0); 
    } 
    return [countPositive, sumNegative]; 
} 

這引發了我一個類型錯誤,說:

類型錯誤:無法讀取屬性「0」的未定義

當我登錄「下一頁」到控制檯在reduce函數內部,除了第一個輸入外,其它日誌都是未定義的。如預期的那樣,第一個是0.但是對於每個後續輸入,其日誌未定義。這是爲什麼發生?

在此先感謝。

回答

4

傳遞給.reduce()回調需要返回的累計值(將作爲prev被傳遞到循環的下一次迭代的價值。既然你什麼都不回來,你會得到undefined爲你的循環的下一次迭代。

這會讓你想要做的事變得複雜,因爲你試圖跟蹤循環中的兩個值,因此,你要麼完全避免使用prev,要麼你必須使它成爲一個數據結構中既有你的價值,你的用法也不是.reduce()的教科書示例,你的代碼可能更簡單,迭代使用.forEach()for/of

function countPositivesSumNegatives(input) { 
    let countPositive = 0; 
    let sumNegative = 0 

    if (!input || input.length === 0){ 
     return []; 
    } else { 
     input.forEach(function(num){ 
     if (num > 0) { 
      ++countPositive; 
     } else { 
      sumNegative += num; 
     }); 
    } 
    return [countPositive, sumNegative]; 
} 
+0

啊,這是有道理的。我記得教我關於reduce()的人強調'迴歸'總是成爲回調的一部分。 – newman

+0

還注意到空數組的條件測試是無效的 – charlietfl

+0

@newman - 我添加了一個使用'.forEach()'的實現,我認爲它比嘗試使'.reduce()適合這裏更簡單。 – jfriend00

0

對不起,但這不是一個很好的實現這個功能。但我們可以按照以下方式更正您的功能;

function countPositivesSumNegatives(input) { 
 
    let countPositive = 0; 
 
    let sumNegative = 0; 
 

 
    if (input === null || input === []){ 
 
     return []; 
 
    } else { 
 
     sumNegative = input.reduce(function(prev,num){ 
 
            if (num > 0) { 
 
             countPositive++; 
 
            } else { 
 
             prev += num; 
 
             } 
 
            return prev; // <---- THE MISSING PART 
 
            }, 0); 
 
     } 
 
    return [countPositive, sumNegative]; 
 
} 
 
var data = [1,2,3,4,5,-4,7,-3]; 
 
console.log(countPositivesSumNegatives(data));

但是在代碼工作得很好,但仍涉及很多問題。當進入像.reduce()這樣的函子時,你應該能夠保持包含在它自身內的everthing,並且不應該引用外部範圍的變量。因此,人們可以簡單地重新編寫這段代碼如下:

var data = [1,2,3,4,5,-4,7,-3], 
 
    cpsn = a => a.reduce((p,c) => c > 0 ? (p[0]++,p) : (p[1]+=c,p) ,[0,0]); 
 
console.log(cpsn(data))