Skip to content

Latest commit

 

History

History
116 lines (80 loc) · 4.07 KB

baseOrderBy.md

File metadata and controls

116 lines (80 loc) · 4.07 KB

lodash源码分析之baseOrderBy

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

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

依赖

import baseEach from './baseEach.js'
import baseSortBy from './baseSortBy.js'
import baseGet from './baseGet.js'
import compareMultiple from './compareMultiple.js'
import isArrayLike from '../isArrayLike.js'

《lodash源码分析之baseEach》 《lodash源码分析之baseSortBy》 《lodash源码分析之baseGet》 《lodash源码分析之compareMultiple》 《lodash源码分析之isArrayLike》

源码分析

baseOrderBy 是用来实现 orderBy 的内部函数,会对参数进行一些合规化处理。

源码如下:

const identity = (value) => value

function baseOrderBy(collection, iteratees, orders) {
  if (iteratees.length) {
    iteratees = iteratees.map((iteratee) => {
      if (Array.isArray(iteratee)) {
        return (value) => baseGet(value, iteratee.length === 1 ? iteratee[0] : iteratee)
      }

      return iteratee
    })
  } else {
    iteratees = [identity]
  }

  let criteriaIndex = -1
  let eachIndex = -1

  const result = isArrayLike(collection) ? new Array(collection.length) : []

  baseEach(collection, (value) => {
    const criteria = iteratees.map((iteratee) => iteratee(value))

    result[++eachIndex] = {
      criteria,
      index: ++criteriaIndex,
      value
    }
  })

  return baseSortBy(result, (object, other) => compareMultiple(object, other, orders))
}

处理 iteratees

iteratees 可以是函数集、字符串集,如果是字符串集,则应该为属性路径,iteratee 的作用是根据传入的 value 值,返回一个新值,来作为排序时的比较值。

有多少个 iteratee,就有多少个维度的比较。

iteratees 的合规化处理源码如下:

if (iteratees.length) {
  iteratees = iteratees.map((iteratee) => {
    if (Array.isArray(iteratee)) {
      return (value) => baseGet(value, iteratee.length === 1 ? iteratee[0] : iteratee)
    }

    return iteratee
  })
} else {
  iteratees = [identity]
}

如果传入的是空数组,则 iteratees 默认为 [identity] ,即每个 iteratee 调用的时候,都是返回值本身。

如果 iteratees 传入的是 [['a', 'b', 'c']] 这样的路径数组,则表示要取 value 上的 a.b.c 路径上的值进行比较。

因为后面 iteratee 会使用函数调用的方式,因此这里使用一个函数来取值:

if (Array.isArray(iteratee)) {
  return (value) => baseGet(value, iteratee.length === 1 ? iteratee[0] : iteratee)
}

baseGet 除了支持数组路径外,也支持如 a.b.c 这样的字符串路径,这时传入的 iteratees 的值类似于 [['a.b.c']]

因此判断 iteratee.length 是否为 1 ,如果长度为 1,则将值取出,直接传入字符串给 baseGet

遍历 collection ,获取所有维度的比较值

如果 collection 为类数组,则先初始化一个长度与 collection 一致的结果集,用来保存排序后的结果。

接着,使用 baseEach 遍历 collection ,每个值 value 都传给所有的 iteratee 函数,计算出所有维度的比较值,结果存入 criteria 中,在排序的时候,会从 criteria 取出来比较。比较的过程在 compareMultiple 函数中已经分析。

最后就是调用 baseSortBy 使用 compareMultiple 作为比较函数来得到排序结果。

License

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

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

作者:对角另一面