js中容易被遗忘的逗号!

455 阅读2分钟

无聊逛github,需求是统计数组中元素出现的个数,使用reduce()可以很轻松实现,我的写法:

const countOccurrences = (arr) => arr.reduce((prev, cur) => {
  if (cur in prev) {
    ++prev[cur]
  } else {
    prev[cur] = 1
  }
  return prev
}, {})

大神的写法:

const countOccurrences = (arr) => arr.reduce((prev, curr) => ((prev[curr] = ++prev[curr] || 1), prev), {});

简单介绍一下 || 或逻辑运算符

  • 当参与运算的任意一个参数为true时,返回true,否则返回false;

  • console.log(true || false) // true
    console.log(false || true) // true
    console.log(true || true) // true
    console.log(false || false) // false
    
  • 那么如果给定多个参数,例如 1 || 2 || 3这种情况呢?直接 show code

  • console.log(1 || 2 || 3) // 1
    console.log(66 || 2 || 3) // 66
    console.log(1 || 0 || 3) // 1
    console.log(null || null || 3) // 3
    
    console.log(null || undefined || 0) // 0
    console.log(null || 0 || undefined) // undefined
    
  • 发现如果结果为true,那么返回第一个真值;如果结果为false,那么返回最后一个值


回过头看代码,(prev[curr] = ++prev[curr] || 1) ,这段现在就很好理解了,但是主要让我疑惑的是,reduce()方法中prev参数是上一次调用回调的返回值,可是这段代码并没有看到return字样,这是怎么回事?难道是逗号?我的印象中,的确依稀记得是存在一个逗号运算符的,查阅了一下,果然没错。

逗号运算符

对它的每个操作数从左到右求值,并返回最后一个操作数的值

直接看代码:

let a = 10
let b = 12
let c = 15
let d
d = (a, b++, c++, 100)
console.log(a, b, c, d) // 10 13 16 100

现在已经大致有了解了,突然想到大四时期刚出去找实习面试的时候,笔试过这么一道题,如今突然茅塞顿开:

var i = j = 0, k = 0;
for(i, j; i < 10, j < 6; i++, j++) {
   k = i + j;
}
console.log(k); // 10

当初天真以为循环结束的条件是i<10 , j<6中,小的那一项,即j>=6时跳出循环,所以蒙对了结果是10。如今看来,这里其实也是应用了逗号运算符,返回最后一项操作数的值,看下面的例子:

var i = j = 0, k = 0;
for(i, j; i < 6, j < 10; i++, j++) {
   k = i + j;
}
console.log(k); 

如果按照我之前的想法,那么调换值的顺序是没有影响的,可是结果输出为18,这也充分说明了的确是逗号运算符搞的鬼,k = 9 + 9 =18,当j=10时,跳出循环。

总结

再次回头看一下我的写法与大神的写法,其实都已经return prev,不过后者的写法看起来更简洁一些,由于本人才疏学浅,第一时间没有反应过来,今天也算是又收获了一个知识点。