2017-04-02 682 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))