今天看到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为什么会报这样的错?谁能回答下这两个问题吗??感激不尽。百度谷歌了好久都找不到答案。。
1 回答
胡子哥哥
语法上的
TA贡献1825条经验 获得超6个赞
先改写一下,让你看得清楚些。
const str = 'ddd'const initialVal = {}let res = str.split('').reduce((pre, cur) => (pre[cur]++ || (pre[cur] = 1), pre), initialVal)
语法上的confusion
可以繁写为:
(pre, cur) => { return pre[cur]++ || (pre[cur] = 1), pre}
形如 return 1, 3, 4
总是返回最后一个合法的值。
这里用这种偏门写法主要是为了能在一行中写完,使其既执行语句,还能返回值pre,供给下一次遍历消费。
算是片面追求短小。
加了注释的ES5写法
var str = 'ddd';// cache 是 reduce 函数进行累加操作时候的初始值。// 在这里,它主要用来缓存字符串中出现的字符和它们的出现次数。 // 遍历结束后,它的结构可能是 { d: 3 } 。var cache = {};var res = str.split('').reduce(function (pre, cur) { // pre 是一个 plain Object, 初始值为 cache ,可能形如 { d: 1 }。 // 而 cur 是当前遍历到的字符,可能为 d。 var cachedTimes = pre[cur]; // 所以这一步是在向buffer(缓存)中询问,是否已经缓存过 d,并且得到它的次数。 if (cachedTimes) { pre[cur] += 1; // 如果有值,说明已经缓存过,加上这次访问,其次数应该 + 1 } else { pre[cur] = 1; // 如果为undefined,说明没有缓存过,在缓存中注册一下,次数为1 } return pre; // 把修改后的 pre 传给下一次遍历消费。}, cache);
在js中,使用cache表来缓存遍历次数是一个常见的优化办法。因为js中访问属性是很快的。
你改写的函数的错误之处
额,其实讲到这里你应该很明白了。然而你的reduce
的回调函数体中并没有返回累计结果,传给下一次遍历。所以第二次遍历时,pre
为undefined
。
你的str
中第二个字符估计是d
,undefined.d
当然报错啦。
PS 这种写法会更优雅吗?
添加回答
举报
0/150
提交
取消