今天看到javascript的函数式编程的一篇文章,讲的是用reduce这个函数统计一个字符串中各字母出现的次数,代码如下:`var res = str.split('')
.reduce((pre, cur) => (pre[cur]++ || (pre[cur] = 1), pre), {})`
然后我不知道上式中箭头函数的右边部分中的pre是什么意思,箭头函数右边不就是要返回的表达式吗,为什么上面上面的式子里面还多了个pre?然后我试着改写了一下:
var res = str.split('')
.reduce(function(pre,cur){
console.log(pre) ;
console.log(cur) ;
if( pre[cur] === 1)
{
pre[cur]++;
} else
pre[cur] = 1;
}, {});
结果报错为:
if( pre[cur] === 1)
^
TypeError: Cannot read property 'd' of undefined
为什么会报这样的错?
谁能回答下这两个问题吗??感激不尽。百度谷歌了好久都找不到答案。。
先改写一下,让你看得清楚些。
语法上的
confusion
可以繁写为:
形如
return 1, 3, 4
总是返回最后一个合法的值。这里用这种偏门写法主要是为了能在一行中写完,使其既执行语句,还能返回值pre,供给下一次遍历消费。
算是片面追求短小。
加了注释的ES5写法
在js中,使用cache表来缓存遍历次数是一个常见的优化办法。因为js中访问属性是很快的。
你改写的函数的错误之处
额,其实讲到这里你应该很明白了。然而你的
reduce
的回调函数体中并没有返回累计结果,传给下一次遍历。所以第二次遍历时,pre
为undefined
。你的
str
中第二个字符估计是d
,undefined.d
当然报错啦。PS 这种写法会更优雅吗?
回复追问
Q1
是的。必须给一个返回值,供下次遍历消费。
Q2
可加可不加,你的源码中加了是因为
arrow function
直接返回一个对象时需要用括号包裹。为了严谨,我们用babel转译一下。
babel的转译码
babel的结果是不加的。
试试执行下面的同类代码
Q3
你分成两步看。
根据
return a, b
总是输出 b 的原则,输出b(即pre)。说实话这种偷懒的语法我也是第一次看到,额,反正业务代码里我是不会这么写的,可阅读性太差了。毕竟是example,当然很fancy了。