lodash源码分析之baseFindIndex中的运算符优先级

我悟出权力本来就是不讲理的——蟑螂就是海米;也悟出要造反,内心必须强大到足以承受任何后果才行。 ——北岛《城门开》

本文为读 lodash 源码的第十篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash

gitbook也会同步仓库的更新,gitbook地址:pocket-lodash

作用与用法

baseFindIndex 是内部方法,其作用类似于ES6的 findIndex,查找符合条件的第一个元素的索引。

baseFindIndex 除了从前向后查找外,还可以从后向前查找。

用法如下:

baseFindIndex([3,1,2], function(val, index, array) {
  return val > 1
}, 1) // 从前向后查找,从索引1开始查找,返回2
baseFindIndex([3,1,2], function(val, index, array) {
  return val > 1
}, 1, true) // 从后向前查找,从索引1开始查找,返回3

源码分析

function baseFindIndex(array, predicate, fromIndex, fromRight) {
  const { length } = array
  let index = fromIndex + (fromRight ? 1 : -1)

  while ((fromRight ? index-- : ++index < length)) {
    if (predicate(array[index], index, array)) {
      return index
    }
  }
  return -1
}

这段代码再次展示了 lodash 的特点,短小精悍!

这次读源码我们从里往外看。

从代码中很容易看到,predicate 是传递进来的函数,在 baseFindIndex 调用该函数,如果返回的结果为真值,则中止查找,返回索引。

运算符优先级

我们再往外看,看看 while 的循环条件:

fromRight ? index-- : ++index < length

现在问题来了,这个三元表达式有两种可能,一种是:

(fromRight ? index-- : ++index) < length

一种是:

fromRight ? index-- : (++index < length)

究竟是那一种呢?这就要看运算符的优化级了,下面这个表是 MDN 上的截图:

这个表将优化级划分成了20个级别,数字越大,优化级越高。

从表中可以看到,比较运算符的优先级为11,而三元表达式(条件运算符)的优化级为4,因此可以确定比较运算符的优先级要比三元表达式的要高,循环条件其实等价于第二种写法。

增减迷局

再往上看,可以看到这句代码:

let index = fromIndex + (fromRight ? 1 : -1)

在向后查找时, index 减少了1,而向前查找时,index 增加了1,为什么要这样做呢?

再结合循环条件看下:

fromRight ? index-- : ++index < length

在向前查找时,使用的是 index-- 表达式的运算结果,向后查找时,使用的是 ++index < lenth 表达式的运算结果。

从上表中也可以看出前缀自增比比较运算符的优化级要高。

前缀自增返回的是自增后的结果,而在循环条件中就要将索引 index 增加1,这样会忽略掉第一个需要遍历的元素,作为补救,在开始遍历前,需要将 index 减少1。

同理,在向前查找时,需要将索引增加1,因为在遍历开始时就已经将索引减少1。

那又为什么向前查找时用的是后缀自减,而不是用前缀自减呢?

因为在向前查找时,最终要查找到数组索引 0 的位置,后缀自减返回的是自减前的数值,因此当 index1 时,自减后的 index0 ,但是在循环条件中依然拿 1 来进行判断,所以使得索引 0 得以进入循环体。

关于前缀自增/减和后缀自增/减的区别可以看《lodash源码分析之自减的两种形式》。

参考

  1. MDN:运算符优先级

License

署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)

最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:

作者:对角另一面

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏灯塔大数据

每周学点大数据 | No.41 join 操作

No.41期 join 操作 Mr. 王:第一个话题就是 join 操作。 join 操作在数据库中还是非常常见的。 小可:这个 join 指的是笛卡儿积操...

3837
来自专栏GIS讲堂

geotools编写shp转sql,实现shp数据入Oracle Spatial库

用到Oracle Spatial就很难避免shp文件的入库问题,虽然有shp2sdo工具,但是用起来不是很习惯,所以,本文讲述如何结合geotools实现shp...

2254
来自专栏性能与架构

Mysql order by排序优化

1. 加大max_length_for_sort_data参数的设置 在MySQL中,排序算法分为两种,一是只加载排序字段到内存,排序完成后再到表中取其他字段,...

3555
来自专栏逆向技术

16位汇编第七讲汇编指令详解第第三讲

                             16位汇编第六讲汇编指令详解第第三讲 1.十进制调整指令 1. 十进制数调整指令对二进制运算的结果进行...

1795
来自专栏王小雷

Python之数据聚合与分组运算

Python之数据聚合与分组运算 1. 关系型数据库方便对数据进行连接、过滤、转换和聚合。 2. Hadley Wickham创建了用于表示分组运算术语“spl...

2449
来自专栏菩提树下的杨过

mybatis的物理分页:mybatis-paginator

文件分割与合并是一个常见需求,比如:上传大文件时,可以先分割成小块,传到服务器后,再进行合并。很多高大上的分布式文件系统(比如:google的GFS、taoba...

2189
来自专栏对角另一面

lodash源码分析之baseFindIndex中的运算符优先级

本文为读 lodash 源码的第十篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash

1998
来自专栏闻道于事

数据库规范与数据类型选择

NUMBER :精度最高可达20个基数-100位,相当于39或40位十进制数,具体取决于小数点的位置。

1703
来自专栏代码世界

Django ORM那些相关操作

一般操作 https://docs.djangoproject.com/en/1.11/ref/models/querysets/         官网文档 常...

4236
来自专栏菩提树下的杨过

java:快速文件分割及合并

文件分割与合并是一个常见需求,比如:上传大文件时,可以先分割成小块,传到服务器后,再进行合并。很多高大上的分布式文件系统(比如:google的GFS、taoba...

4599

扫码关注云+社区

领取腾讯云代金券