lodash已死?radash最全使用介绍(附源码说明)—— Array方法篇(3)

前言

  • 我们已经介绍了radash的相关信息和部分Array相关方法,详情可前往主页查看;
  • 本篇我们继续介绍radash中Array的相关方法;
  • 下期我们将介绍解析radash中剩余的 Array相关方法,并整理出Array方法使用目录,包括文章说明脑图说明

Radash的Array相关方法详解

iterate:把一个函数迭代执行指定次数

  1. 使用说明

    • 参数:迭代次数、每次迭代调用的函数、迭代初始值。
    • 返回值:返回最终一次循环迭代的值。
  2. 使用代码示例

    import { iterate } from 'radash'
    
    const value = iterate(
      4,
      (acc, idx) => {
        return acc + idx
      },
      0
    ) // => 10
    
  3. 源码解析

    // 定义一个泛型函数 `iterate`,它接收三个参数:
    // `count` 是一个数字,表示迭代的次数;
    // `func` 是一个函数,它在每次迭代中被调用,接收当前值和迭代次数作为参数,并返回一个新的值;
    // `initValue` 是迭代的初始值,它的类型为泛型 `T`。
    export const iterate = <T>(
      count: number,
      func: (currentValue: T, iteration: number) => T,
      initValue: T
    ) => {
      // 初始化一个变量 `value`,用于存储当前的迭代值,起始值设置为 `initValue`。
      let value = initValue
      // 使用一个 `for` 循环进行 `count` 次迭代。循环变量 `i` 从 1 开始,以确保迭代次数正确。
      for (let i = 1; i <= count; i++) {
        // 在每次迭代中,调用函数 `func`,传入当前的 `value` 和迭代次数 `i`,
        // 然后将 `func` 函数返回的新值赋给 `value`,以便在下一次迭代中使用。
        value = func(value, i)
      }
      // 循环结束后,返回最终的迭代值 `value`。
      return value
    }
    
    • 方法流程说明:
      1. 接收 countfuncinitValue 作为参数。
      2. 初始化变量 valueinitValue
      3. 进行 count 次迭代,每次迭代中调用 func 函数,传入当前的 value 和迭代次数 i
      4. func 函数返回一个新值,这个新值成为下一次迭代的 value
      5. 迭代完成后,返回最后一次 func 函数调用的结果。

last:输出数组的最后一项,如果数组为空则输出传入的默认值

  1. 使用说明

    • 参数:目标数组,或者空数组和默认值。
    • 返回值:数组最后一项,如果数组为空则输出传入的默认值。
  2. 使用代码示例

    import { last } from 'radash'
    
    const fish = ['marlin', 'bass', 'trout']
    
    const lastFish = last(fish) // => 'trout'
    const lastItem = last([], 'bass') // => 'bass'
    
  3. 源码解析

    // 定义一个泛型函数 `last`,它接收一个具有只读属性的泛型数组 `array`,
    // 和一个可选的默认值 `defaultValue`,其类型可以是泛型 `T` 或 `null` 或 `undefined`,默认值为 `undefined`。
    export const last = <T>(
      array: readonly T[],
      defaultValue: T | null | undefined = undefined
    ) => {
      // 如果数组存在且长度大于0,返回数组的最后一个元素。
      // 否则,返回提供的默认值 `defaultValue`。
      return array?.length > 0 ? array[array.length - 1] : defaultValue
    }
    
    • 方法流程说明:
      1. 检查传入的数组 array 是否存在且长度大于0。
      2. 如果数组存在且不为空(长度大于0),则返回数组的最后一个元素 array[array.length - 1]
      3. 如果数组不存在或为空,返回 defaultValue
      4. 这个函数对于需要安全地访问数组最后一个元素而不抛出错误的情况很有用,特别是在不确定数组是否为空的情况下。通过提供一个默认值,你可以避免在数组为空时访问未定义的索引。如果没有提供默认值,函数将默认返回 undefined

list:创建包含特定项的数组

  1. 使用说明

    • 参数:start、end、值,步长。
    • 返回值:从start开始遍历到end,输出一个数组,包含特定项(值)的数组。
  2. 使用代码示例

    import { list } from 'radash'
    
    list(3)                  // [0, 1, 2, 3]
    list(0, 3)               // [0, 1, 2, 3]
    list(0, 3, 'y')          // [y, y, y, y]
    list(0, 3, () => 'y')    // [y, y, y, y]
    list(0, 3, i => i)       // [0, 1, 2, 3]
    list(0, 3, i => `y${i}`) // [y0, y1, y2, y3]
    list(0, 3, obj)          // [obj, obj, obj, obj]
    list(0, 6, i => i, 2)    // [0, 2, 4, 6]
    
  3. 源码解析

    // 定义一个泛型函数 `list`,它接受一个默认类型参数 `T`,默认为 `number`。
    // 函数接受四个参数:起始值或长度 `startOrLength`,可选的结束值 `end`,
    // 可选的值或映射函数 `valueOrMapper` 用于生成数组中的值,以及可选的步长 `step`。
    export const list = <T = number>(
      startOrLength: number,
      end?: number,
      valueOrMapper?: T | ((i: number) => T),
      step?: number
    ): T[] => {
      // 使用 `Array.from` 方法来创建一个数组,它接受 `range` 生成器函数作为参数。
      // `range` 函数根据提供的参数生成一个序列的值。
      return Array.from(range(startOrLength, end, valueOrMapper, step))
    }
    
    • 方法流程说明:
      1. 调用 range 函数,传入 startOrLength(起始值或长度)、end(结束值)、valueOrMapper(值或映射函数)、step(步长)四个参数。这些参数都是可选的,除了 startOrLength 必须提供。
      2. range 函数是一个生成器,根据提供的参数生成一个数字序列。如果指定了 end,那么 startOrLength 作为起始值,end 作为结束值。如果没有指定 endstartOrLength 作为序列的长度。valueOrMapper 可以是一个值,此时序列中的每个元素都是这个值;也可以是一个函数,此时序列中的每个元素都是这个函数的返回值。step 指定了序列中每个元素之间的间隔。
      3. Array.from 方法用于从 range 生成器创建一个数组。生成器的每次迭代返回的值都会成为数组中的一个元素。
      4. 最终,list 函数返回这个数组。

max:获取对象数组中指定标识符最大的项

  1. 使用说明

    • 参数:目标对象数组、指定标识符的回调函数。
    • 返回值:符合条件的对象。
  2. 使用代码示例

    import { max } from 'radash'
    
    const fish = [
      {
        name: 'Marlin',
        weight: 105,
        source: 'ocean'
      },
      {
        name: 'Bass',
        weight: 8,
        source: 'lake'
      },
      {
        name: 'Trout',
        weight: 13,
        source: 'lake'
      }
    ]
    
    max(fish, f => f.weight) // => {name: "Marlin", weight: 105, source: "ocean"}
    
  3. 源码解析

    // 定义一个泛型函数 `max`,它接受一个具有只读属性的泛型数组 `array`,
    // 以及一个可选的函数 `getter`,该函数用于从数组元素中提取一个数字用于比较大小。
    export function max<T>(
      array: readonly T[],
      getter?: (item: T) => number
    ): T | null {
      // 如果 `getter` 函数未提供,则使用默认函数,它将元素作为其自己的值。
      const get = getter ?? ((v: any) => v)
      // 调用 `boil` 函数,传入数组和一个比较函数,
      // 比较函数用 `get` 函数获取的值来决定哪个元素更大。
      return boil(array, (a, b) => (get(a) > get(b) ? a : b))
    }
    
    // 定义一个泛型函数 `boil`,它接受一个具有只读属性的泛型数组 `array`,
    // 以及一个比较函数 `compareFunc`,该函数用于比较两个元素并返回其中一个。
    export const boil = <T>(
      array: readonly T[],
      compareFunc: (a: T, b: T) => T
    ) => {
      // 如果传入的数组不存在,或者其长度为0,则返回 null。
      if (!array || (array.length ?? 0) === 0) return null
      // 使用数组的 `reduce` 方法应用 `compareFunc`,将数组归约为单一的值。
      return array.reduce(compareFunc)
    }
    
    • 方法流程说明:
      1. 接收一个数组 array 和一个可选的 getter 函数。如果 getter 函数提供,它将用于从每个元素中提取用于比较的数字值。
      2. 如果没有提供 getter 函数,使用一个默认的函数,这个函数简单地返回元素本身作为比较值。
      3. 调用 boil 函数,传入数组和一个比较函数。这个比较函数使用 get 函数从两个元素 ab 中提取值,并返回较大值对应的元素。
      4. boil 函数通过 reduce 方法遍历数组,应用比较函数,并最终返回单一的元素,即数组中的最大元素。如果数组为空或未定义,boil 函数返回 null
      5. max 函数最终返回 boil 函数的结果,即数组中的最大元素,如果数组为空,则返回 null

merge:合并数组中符合条件的项,并且会覆盖第一个数组

  1. 使用说明

    • 参数:数组1、数组2、条件函数。
    • 返回值:合并覆盖后的数组。
  2. 使用代码示例

    import { merge } from 'radash'
    
    const gods = [
      {
        name: 'Zeus',
        power: 92
      },
      {
        name: 'Ra',
        power: 97
      }
    ]
    
    const newGods = [
      {
        name: 'Zeus',
        power: 100
      }
    ]
    
    merge(gods, newGods, f => f.name) // => [{name: "Zeus" power: 100}, {name: "Ra", power: 97}]
    
  3. 源码解析

    export const merge = <T>(
      root: readonly T[],
      others: readonly T[],
      matcher: (item: T) => any
    ) => {
      if (!others && !root) return []
      if (!others) return root
      if (!root) return []
      if (!matcher) return root
      return root.reduce((acc, r) => {
        const matched = others.find(o => matcher(r) === matcher(o))
        if (matched) acc.push(matched)
        else acc.push(r)
        return acc
      }, [] as T[])
    }
    
    • 方法流程说明:
      1. 进行一系列的检查,如果 othersroot 两个数组都不存在或为空,或者没有提供 matcher 函数,就返回 root 或者一个空数组。
      2. 使用 root 数组的 reduce 方法构建最终的合并数组。在每次迭代中,使用 matcher 函数检查 root 数组中的当前元素是否在 others 数组中有匹配的元素。
      3. 如果在 others 数组中找到了一个匹配的元素,就把这个匹配的元素添加到累加器数组 acc 中。
      4. 如果没有找到匹配的元素,就把 root 数组中的当前元素添加到累加器 acc 中。
      5. 继续处理 root 数组的下一个元素,直到所有元素都被处理完毕。
      6. 返回累加器 acc,它现在包含了合并后的元素。

min:获取对象数组中指定标识符最小的项

  1. 使用说明

    • 参数:目标对象数组、指定标识符的条件函数。
    • 返回值:符合条件的的项
  2. 使用代码示例

    import { min } from 'radash'
    
    const fish = [
      {
        name: 'Marlin',
        weight: 105,
        source: 'ocean'
      },
      {
        name: 'Bass',
        weight: 8,
        source: 'lake'
      },
      {
        name: 'Trout',
        weight: 13,
        source: 'lake'
      }
    ]
    
    min(fish, f => f.weight) // => {name: "Bass", weight: 8, source: "lake"}
    
  3. 源码解析

    // 这是 `min` 函数的第一种声明,它要求传递一个 `getter` 函数。
    export function min<T>(
      array: readonly T[],
      getter: (item: T) => number
    ): T | null
    
    // 这是 `min` 函数的第二种声明,它允许 `getter` 函数是可选的。
    export function min<T>(
      array: readonly T[],
      getter?: (item: T) => number
    ): T | null {
      // 如果没有提供 `getter` 函数,使用默认函数,它将元素作为其自己的值。
      const get = getter ?? ((v: any) => v)
      // 调用 `boil` 函数,传入数组和一个比较函数,
      // 比较函数用 `get` 函数获取的值来决定哪个元素更小。
      return boil(array, (a, b) => (get(a) < get(b) ? a : b))
    }
    
    • 方法流程说明:
      1. 函数接收一个数组 array 和一个可选的 getter 函数。如果提供了 getter 函数,它将用于从每个元素中提取用于比较的数字值。
      2. 如果没有提供 getter 函数,则使用一个默认的函数,这个函数简单地返回元素本身作为比较值。
      3. 调用 boil 函数,传入数组和一个比较函数。这个比较函数使用 get 函数从两个元素 ab 中提取值,并返回较小值对应的元素。
      4. boil 函数通过 reduce 方法遍历数组,应用比较函数,并最终返回单一的元素,即数组中的最小元素。如果数组为空或未定义,boil 函数返回 null
      5. min 函数最终返回 boil 函数的结果,即数组中的最小元素,如果数组为空,则返回 null

objectify:根据函数映射的键与值把数组转换为字典对象

  1. 使用说明

    • 参数:目标对象数组、条件函数1用于提取键、[条件函数2用于提取值]
    • 返回值:字典对象
  2. 使用代码示例

    import { objectify } from 'radash'
    
    const fish = [
      {
        name: 'Marlin',
        weight: 105
      },
      {
        name: 'Bass',
        weight: 8
      },
      {
        name: 'Trout',
        weight: 13
      }
    ]
    
    objectify(fish, f => f.name) // => { Marlin: [marlin object], Bass: [bass object], ... }
    objectify(
      fish,
      f => f.name,
      f => f.weight
    ) // => { Marlin: 105, Bass: 8, Trout: 13 }
    
  3. 源码解析

    // 定义一个泛型函数 `objectify`,它接受三个参数:
    // `array` 是一个具有只读属性的泛型数组,
    // `getKey` 是一个函数,用于从数组元素中提取键,
    // `getValue` 是一个可选的函数,用于从数组元素中提取值,默认情况下,它会返回元素本身作为值。
    export const objectify = <T, Key extends string | number | symbol, Value = T>(
      array: readonly T[],
      getKey: (item: T) => Key,
      getValue: (item: T) => Value = item => item as unknown as Value
    ): Record<Key, Value> => {
      // 使用数组的 `reduce` 方法来累积一个对象,该对象将数组元素映射为键值对。
      return array.reduce((acc, item) => {
        // 使用 `getKey` 函数从当前元素 `item` 中提取键,并使用 `getValue` 函数提取值。
        // 将这个键值对添加到累加器对象 `acc` 中。
        acc[getKey(item)] = getValue(item)
        // 返回更新后的累加器 `acc`。
        return acc
      }, {} as Record<Key, Value>) // 初始化累加器 `acc` 为一个空对象。
    }
    
    • 方法流程说明:
      1. 函数接收一个数组 array,一个 getKey 函数用于提取每个元素的键,以及一个可选的 getValue 函数用于提取每个元素的值。
      2. 如果没有提供 getValue 函数,则使用一个默认的函数,这个函数简单地将元素本身作为值。
      3. 使用 reduce 方法遍历数组。reduce 方法的累加器 acc 是一个对象,用于存储键值对。
      4. 对于数组中的每个元素 item,使用 getKey 函数提取键,并使用 getValue 函数提取值。
      5. 将提取的键和值作为一个键值对添加到累加器对象 acc 中。
      6. 继续处理数组的下一个元素,直到所有元素都被处理完毕。
      7. 返回累加器 acc,它现在是一个完整的对象,包含了从数组元素映射而来的键值对。

range:根据步长生成一个数值范围内的迭代值

  1. 使用说明

    • 参数:起始值、[结束值]、[迭代函数]、步长。
    • 返回值:用在for循环中循环输出处理的结果值。
  2. 使用代码示例

    import { range } from 'radash'
    
    range(3)                  // yields 0, 1, 2, 3
    range(0, 3)               // yields 0, 1, 2, 3
    range(0, 3, 'y')          // yields y, y, y, y
    range(0, 3, () => 'y')    // yields y, y, y, y
    range(0, 3, i => i)       // yields 0, 1, 2, 3
    range(0, 3, i => `y${i}`) // yields y0, y1, y2, y3
    range(0, 3, obj)          // yields obj, obj, obj, obj
    range(0, 6, i => i, 2)    // yields 0, 2, 4, 6
    
    for (const i of range(0, 200, 10)) {
      console.log(i) // => 0, 10, 20, 30 ... 190, 200
    }
    
    for (const i of range(0, 5)) {
      console.log(i) // => 0, 1, 2, 3, 4, 5
    }
    
  3. 源码解析

    // 定义一个泛型生成器函数 `range`,它接受一个默认类型参数 `T`,默认为 `number`。
    // 函数接受四个参数:起始值或长度 `startOrLength`,可选的结束值 `end`,
    // 可选的值或映射函数 `valueOrMapper` 用于生成序列中的值,以及可选的步长 `step`,默认为 1。
    export function* range<T = number>(
      startOrLength: number,
      end?: number,
      valueOrMapper: T | ((i: number) => T) = i => i as T,
      step: number = 1
    ): Generator<T> {
      // 确定 `valueOrMapper` 是一个函数还是一个固定值。如果是函数,则直接使用;如果不是,则创建一个总是返回该值的函数。
      const mapper = isFunction(valueOrMapper) ? valueOrMapper : () => valueOrMapper
      // 如果提供了 `end` 值,则 `start` 为 `startOrLength`;如果没有提供 `end` 值,则 `start` 默认为 0。
      const start = end ? startOrLength : 0
      // `final` 是序列的结束值,如果提供了 `end` 值,则使用它;如果没有,则 `final` 为 `startOrLength`。
      const final = end ?? startOrLength
      // 从 `start` 开始,到 `final` 结束,每次迭代增加 `step`。
      for (let i = start; i <= final; i += step) {
        // 使用 `yield` 关键字产生由 `mapper` 函数处理的当前迭代值 `i`。
        yield mapper(i)
        // 如果下一次增加步长后的值会超过 `final`,则提前终止循环。
        if (i + step > final) break
      }
    }
    
    • 方法流程说明:
      1. 确定 valueOrMapper 参数是一个函数还是一个值。如果是函数,直接用作映射器;如果是值,创建一个总是返回该值的函数作为映射器。
      2. 确定起始值 start。如果提供了 end 参数,startstartOrLength;否则 start 默认为 0。
      3. 确定结束值 final。如果提供了 end 参数,finalend;否则 finalstartOrLength
      4. 使用一个 for 循环从 start 遍历到 final,每次迭代增加步长 step
      5. 在每次迭代中,使用 yield 关键字来产出 mapper 函数处理过的当前值。
      6. 如果在下一次迭代步长加上当前值 i 会超过 final,则提前退出循环。
      7. 提示:这个 range 函数提供了类似于 Python 中的 range 函数的功能,允许在迭代中产生一系列的值。通过使用生成器,我们可以惰性地产生这些值,这意味着直到迭代器被消费时,这些值才会被计算和产生。这在处理大范围的值时非常有用,因为它不需要一次性将所有值加载到内存中。

replaceOrAppend:替换对象数组中的项或是追加项(条件函数不满足时追加);

  1. 使用说明

    • 参数:被替换数组、用来的替换的数组、条件函数。
    • 返回值:替换或者追加后的数组。
  2. 使用代码示例

    import { replaceOrAppend } from 'radash'
    
    const fish = [
      {
        name: 'Marlin',
        weight: 105
      },
      {
        name: 'Salmon',
        weight: 19
      },
      {
        name: 'Trout',
        weight: 13
      }
    ]
    
    const salmon = {
      name: 'Salmon',
      weight: 22
    }
    
    const sockeye = {
      name: 'Sockeye',
      weight: 8
    }
    
    replaceOrAppend(fish, salmon, f => f.name === 'Salmon') // => [marlin, salmon (weight:22), trout]
    replaceOrAppend(fish, sockeye, f => f.name === 'Sockeye') // => [marlin, salmon, trout, sockeye]
    
  3. 源码解析

    // 定义一个泛型函数 `replaceOrAppend`,它接受三个参数:
    // `list` 是一个具有只读属性的泛型数组,
    // `newItem` 是一个新的元素,将被添加到数组中,
    // `match` 是一个函数,用于确定新元素应该替换数组中的哪个现有元素。
    export const replaceOrAppend = <T>(
      list: readonly T[],
      newItem: T,
      match: (a: T, idx: number) => boolean
    ) => {
      // 如果 `list` 和 `newItem` 都不存在或为空,则返回一个空数组。
      if (!list && !newItem) return []
      // 如果 `newItem` 不存在或为空,则返回 `list` 数组的副本。
      if (!newItem) return [...list]
      // 如果 `list` 不存在或为空,则返回一个只包含 `newItem` 的数组。
      if (!list) return [newItem]
      // 遍历 `list` 数组,寻找一个匹配的元素。
      for (let idx = 0; idx < list.length; idx++) {
        const item = list[idx]
        // 如果 `match` 函数返回 `true`,则在该位置替换元素。
        if (match(item, idx)) {
          // 创建一个新数组,其中包含从 `list` 开始到匹配位置之前的所有元素,
          // 然后是 `newItem`,然后是从匹配位置之后到 `list` 结束的所有元素。
          return [
            ...list.slice(0, idx),
            newItem,
            ...list.slice(idx + 1, list.length)
          ]
        }
      }
      // 如果没有找到匹配的元素,将 `newItem` 追加到 `list` 数组的末尾。
      return [...list, newItem]
    }
    
    • 方法流程说明:
      1. 进行一系列的检查,如果 listnewItem 都不存在或为空,或者只有 newItem 不存在或为空,或者只有 list 不存在或为空,则返回相应的结果。
      2. 如果 listnewItem 都存在,遍历 list 数组,对于每个元素和它的索引,调用 match 函数。
      3. 如果 match 函数对某个元素返回 true,说明找到了应该被替换的元素。函数将创建一个新数组,该数组由以下部分组成:从 list 的开始到匹配元素之前的部分,newItem,以及从匹配元素之后到 list 结尾的部分。
      4. 如果遍历完成后没有找到任何匹配的元素,函数将 newItem 添加到 list 的末尾,并返回新数组。

下期我们将介绍 radash 中剩余的数组相关方法

  • replace :查找指定项,并用传入的去替换;
  • select :对数组同时进行过滤和映射,输出映射后的value数组;
  • shift :把目标数组向右移动 n 个位置返回为一个新数组;
  • sift:过滤调列表中值为false的项,返回剩余为true的项组成的数组;
  • sort :把数组按照条件函数指定的项的数值大小排序,支持升序和降序;
  • sum:数组对象根据条件函数指定想的数组求和;
  • toggle:查找数组中是否有我们给定的项,有则删除,没有则添加;
  • unique:数组去重,去除数组中重复的项;
  • zipToObject:将第一个数组中的键映射到第二个数组中对应的值;
  • zip:把两个数组变为二维数组,二维数组中的每个数组包含两个项分别为两个传入数组的相同位置的项。

写在后面

  • 后续作者会整理一份radash完整方法目录上传,方便没法访问外网的朋友查看使用。
  • 下期方法分享完后,会同步整理分享Array方法的使用说明目录,方便大家查阅对照使用。
  • 小tips:不出意外的话博主每周五会定时更新,出意外的话就是出意外了。
  • 大家有任何问题或见解,欢迎评论区留言交流和批评指正!!!
  • 点击访问:radash官网
相关推荐
黑客老陈1 小时前
新手小白如何挖掘cnvd通用漏洞之存储xss漏洞(利用xss钓鱼)
运维·服务器·前端·网络·安全·web3·xss
正小安1 小时前
Vite系列课程 | 11. Vite 配置文件中 CSS 配置(Modules 模块化篇)
前端·vite
暴富的Tdy1 小时前
【CryptoJS库AES加密】
前端·javascript·vue.js
neeef_se1 小时前
Vue中使用a标签下载静态资源文件(比如excel、pdf等),纯前端操作
前端·vue.js·excel
m0_748235612 小时前
web 渗透学习指南——初学者防入狱篇
前端
z千鑫2 小时前
【前端】入门指南:Vue中使用Node.js进行数据库CRUD操作的详细步骤
前端·vue.js·node.js
m0_748250743 小时前
Web入门常用标签、属性、属性值
前端
m0_748230443 小时前
SSE(Server-Sent Events)返回n ,前端接收数据时被错误的截断【如何避免SSE消息中的换行符或回车符被解释为事件消息的结束】
前端