lodash已死?radash库方法介绍及源码解析 —— 对象方法篇

2024-05-26 03:20

本文主要是介绍lodash已死?radash库方法介绍及源码解析 —— 对象方法篇,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

assign:递归合并两个对象

  1. 使用说明

  • 功能说明:类似于 JavaScript 的 Object.assign 方法,用于将 override 对象的属性和值复制到 initial 对象中。如果属性值是对象,则递归地进行赋值。

  • 参数:初始对象、覆盖对象。

  • 返回值:返回合并后的新对象

  1. 使用代码示例

import { assign } from 'radash'const ra = {name: 'Ra',power: 100
}assign(ra, { name: 'Loki' })
// => { name: Loki, power: 100 }

  1. 源码解析

// 定义一个泛型函数 `assign`。
export const assign = <X extends Record<string | symbol | number, any>>(// `initial` 是初始对象,它的属性可能被 `override` 对象中的属性覆盖。initial: X,// `override` 是覆盖对象,其属性将覆盖或添加到 `initial` 对象中。override: X
): X => {// 如果 `initial` 或 `override` 为空,则返回非空的那个,或者如果都为空则返回一个空对象。if (!initial || !override) return initial ?? override ?? {}// 使用 `Object.entries` 和 `reduce` 方法合并 `initial` 和 `override` 对象。return Object.entries({ ...initial, ...override }).reduce((acc, [key, value]) => {// 在每次迭代中,构建累加器 `acc`,它是最终返回的新对象。return {...acc,[key]: (() => {// 如果 `initial` 中的对应属性是一个对象,则递归地调用 `assign` 进行合并。if (isObject(initial[key])) return assign(initial[key], value)// 如果属性值是数组,这里有一个注释掉的代码行,似乎是未完成的逻辑。// if (isArray(value)) return value.map(x => assign)// 对于非对象属性,直接使用 `override` 中的值。return value})()}},{} as X // 初始累加器是一个类型为 `X` 的空对象。)
}

  • 方法流程说明:

  • assign 函数接受两个参数,initial 和 override,它们都是对象。

  • 如果其中一个对象为空,函数将返回另一个非空对象。

  • 如果两个对象都为空,函数返回一个空对象。如果两个对象都非空,函数使用 Object.entries 和 reduce 方法遍历 override 对象的所有属性。

  • 对于每个属性,如果 initial 对象中对应的属性也是一个对象,则递归地调用 assign 函数来合并这两个对象。

  • 如果 initial 对象中对应的属性不是对象,或 override 对象中的属性在 initial 对象中不存在,则直接使用 override 对象中的值。

  • 返回合并后的新对象。

clone:浅拷贝对象

  1. 使用说明

  • 功能说明:这个函数接受一个对象 obj 作为参数,并返回这个对象的一个新的浅拷贝。

  • 参数:需要克隆的对象。

  • 返回值:过滤完后的映射值组成的数组。

  1. 使用代码示例

import { clone } from 'radash'const ra = {name: 'Ra',power: 100
}const gods = [ra]clone(ra) // => copy of ra
clone(gods) // => copy of gods

  1. 源码解析

// 定义一个泛型函数 `clone`。
export const clone = <T>(obj: T): T => {// 如果 `obj` 是原始值(如数字、字符串或布尔值),则不需要克隆,直接返回 `obj`。if (isPrimitive(obj)) {return obj}// 如果 `obj` 是一个函数,则通过 `bind` 方法创建一个新的绑定函数,// 并将其绑定到一个空对象上,以创建一个函数的副本。if (typeof obj === 'function') {return obj.bind({})}// 获取 `obj` 的构造函数,并使用 `new` 操作符创建一个新的对象实例。// 这个方法同样适用于创建数组的副本。const newObj = new ((obj as object).constructor as { new (): T })()// 遍历 `obj` 的所有自有属性,并将它们复制到新对象 `newObj` 中。Object.getOwnPropertyNames(obj).forEach(prop => {// 这里使用了类型断言 `(newObj as any)` 和 `(obj as any)` 来绕过类型检查,// 因为函数开头已经检查了原始值的情况。;(newObj as any)[prop] = (obj as any)[prop]})// 返回新创建的对象 `newObj`。return newObj
}

  • 方法流程说明:

  • 如果 obj 是一个原始值,直接返回它,因为原始值在JavaScript中是不可变的。

  • 如果 obj 是一个函数,使用 bind 方法创建并返回一个新的函数副本。

  • 如果 obj 是一个对象或数组,使用 obj 的构造函数创建一个新的空对象或空数组 newObj

  • 遍历 obj 的自有属性,并将每个属性值复制到 newObj 中。

  • 返回新对象 newObj

construct:把扁平对象构建为深层对象(多维)

  1. 使用说明

  • 功能说明:这个函数接受一个对象 obj 作为参数,并返回这个对象的一个新的浅拷贝。

  • 参数:键值对对象。

  • 返回值:构建后的新对象。

  1. 使用代码示例

import { construct } from 'radash'const flat = {name: 'ra',power: 100,'friend.name': 'loki','friend.power': 80,'enemies.0.name': 'hathor','enemies.0.power': 12
}construct(flat)
// {
//   name: 'ra',
//   power: 100,
//   friend: {
//     name: 'loki',
//     power: 80
//   },
//   enemies: [
//     {
//       name: 'hathor',
//       power: 12
//     }
//   ]
// }

  1. 源码解析

// 定义一个泛型函数 `construct`。
export const construct = <TObject extends object>(obj: TObject): object => {// 如果 `obj` 为空,则直接返回一个新的空对象。if (!obj) return {}// 使用 `Object.keys` 获取 `obj` 的所有自有属性的键名,// 然后使用 `reduce` 方法来构建新对象。return Object.keys(obj).reduce((acc, path) => {// 对每个属性键名 `path`,调用 `set` 函数来设置新对象 `acc` 的属性。// `(obj as any)[path]` 获取 `obj` 中对应属性的值。// `set` 函数的具体实现未提供,我们可以假设它正确地设置了 `acc` 的属性。return set(acc, path, (obj as any)[path])}, {}) // 初始累加器 `acc` 是一个空对象。
}

  • 方法流程说明:

  • construct 函数接受一个对象 obj 作为参数。

  • 如果 obj 为空,函数返回一个空对象。

  • 如果 obj 非空,函数遍历 obj 的所有自有属性。

  • 对于每个属性,函数使用 set 函数将 obj 中的属性值复制到新对象中。

  • 返回构建完成的新对象。

crush:把深层(多维)对象构建成扁平对象(construct的相反操作)

  1. 使用说明

  • 功能说明:这个函数接受一个对象 obj 作为参数,并返回这个对象的一个新的浅拷贝。

  • 参数:对象。

  • 返回值:构建后的扁平数组。

  1. 使用代码示例

import { crush } from 'radash'const ra = {name: 'ra',power: 100,friend: {name: 'loki',power: 80},enemies: [{name: 'hathor',power: 12}]
}crush(ra)
// {
//   name: 'ra',
//   power: 100,
//   'friend.name': 'loki',
//   'friend.power': 80,
//   'enemies.0.name': 'hathor',
//   'enemies.0.power': 12
// }

  1. 源码解析

// 定义一个泛型函数 `crush`。
export const crush = <TValue extends object>(value: TValue): object => {// 如果 `value` 为空,则直接返回一个空对象。if (!value) return {}// 使用 `objectify` 函数来构建新对象。// `objectify` 函数的具体实现未提供,我们可以假设它以某种方式构建对象。return objectify(// 使用 `keys` 函数获取 `value` 的所有键名。// `keys` 函数的具体实现未提供,我们可以假设它返回对象的所有键名。keys(value),// 使用标识函数 `k => k` 作为键生成函数,意味着新对象的键将与原始对象的键相同。k => k,// 使用 `get` 函数获取 `value` 对象中每个键对应的值。// `get` 函数的具体实现未提供,我们可以假设它正确地获取了对象中的属性值。k => get(value, k))
}

  • 方法流程说明:

  • crush 函数接受一个对象 value 作为参数。

  • 如果 value 为空,函数返回一个空对象。

  • 如果 value 非空,函数使用 keys 函数获取 value 的所有键名。

  • 函数调用 objectify,传入键名数组、键生成函数(这里是标识函数 k => k)和值生成函数(通过调用 get(value, k) 获取每个键的值)。

  • objectify 函数返回一个新对象,这个对象的属性和值与 value 相同。

get:获取对象中的任意属性,可以通过 . 的方式获取深层的属性

  1. 使用说明

  • 功能说明:用于安全地访问嵌套对象的属性,即使某些中间属性不存在也不会抛出错误。如果找不到指定的路径,则返回一个默认值。

  • 参数:目标对象、属性字符(可以.表示深层次属性)、默认值。

  • 返回值:找到则返回指定值,否则返回默认值。

  1. 使用代码示例

import { get } from 'radash'const fish = {name: 'Bass',weight: 8,sizes: [{maturity: 'adult',range: [7, 18],unit: 'inches'}]
}get( fish, 'sizes[0].range[1]' ) // 18
get( fish, 'sizes.0.range.1' ) // 18
get( fish, 'foo', 'default' ) // 'default'

  1. 源码解析

// 定义一个泛型函数 `get`。
export const get = <TDefault = unknown>(// 第一个参数 `value` 是一个任意类型的值,它是要访问属性的对象。value: any,// 第二个参数 `path` 是一个字符串,表示对象属性的路径,使用点或方括号表示法。path: string,// 第三个可选参数 `defaultValue` 是一个默认值,如果无法访问路径,则返回此值。defaultValue?: TDefault
): TDefault => {// 使用正则表达式分割路径字符串,得到一个属性名的数组 `segments`。const segments = path.split(/[.[]]/g)// 初始化一个变量 `current`,用于遍历属性路径。let current: any = value// 遍历 `segments` 中的每个属性名 `key`。for (const key of segments) {// 如果 `current` 是 `null` 或 `undefined`,则返回 `defaultValue`。if (current === null || current === undefined) return defaultValue as TDefault// 移除属性名中的引号。const dequoted = key.replace(/['"]/g, '')// 如果属性名为空(可能是由于路径字符串中的多余点或方括号),则跳过此迭代。if (dequoted.trim() === '') continue// 将 `current` 更新为当前属性名 `dequoted` 对应的值。current = current[dequoted]}// 如果最终的 `current` 是 `undefined`,则返回 `defaultValue`。if (current === undefined) return defaultValue as TDefault// 否则,返回找到的值。return current
}

  • 方法流程说明:

  • get 函数接受一个对象 value,一个表示属性路径的字符串 path,以及一个可选的默认值 defaultValue

  • 使用正则表达式分割 path 字符串,得到一个表示属性链的数组 segments。遍历 segments 数组,依次访问每个属性。

  • 如果在访问过程中遇到 null 或 undefined,或者到达路径的末尾但找不到值,则返回 defaultValue

  • 如果成功访问到路径上的所有属性,并找到了值,则返回这个值。

invert:把对象中的keyvalue对调

  1. 使用说明

  • 功能说明:用于反转对象的键和值。这意味着原始对象的键成为新对象的值,原始对象的值成为新对象的键。

  • 参数:需要反转的对象。

  • 返回值:反转后的新数组。

  1. 使用代码示例

import { invert } from 'radash'const powersByGod = {ra: 'sun',loki: 'tricks',zeus: 'lighning'
}invert(gods) // => { sun: ra, tricks: loki, lightning: zeus }

  1. 源码解析

// 定义一个泛型函数 `invert`。
export const invert = <// 泛型 `TKey` 表示对象的键的类型。TKey extends string | number | symbol,// 泛型 `TValue` 表示对象的值的类型。TValue extends string | number | symbol
>(// 参数 `obj` 是一个对象,其键的类型为 `TKey`,值的类型为 `TValue`。obj: Record<TKey, TValue>
): Record<TValue, TKey> => {// 如果 `obj` 为空,则返回一个空对象。if (!obj) return {} as Record<TValue, TKey>// 使用 `Object.keys` 获取 `obj` 的所有键,并断言键的类型为 `TKey`。const keys = Object.keys(obj) as TKey[]// 使用 `reduce` 方法遍历所有键,创建一个新对象,其键为 `obj` 的值,值为 `obj` 的键。return keys.reduce((acc, key) => {// 将 `obj` 的值 `obj[key]` 作为新对象 `acc` 的键,原始键 `key` 作为新对象的值。acc[obj[key]] = key// 返回累加器 `acc`,它是正在构建的反转对象。return acc}, {} as Record<TValue, TKey>) // 初始累加器是一个空对象,类型为 `Record<TValue, TKey>`。
}

  • 方法流程说明:

  • invert 函数接受一个对象 obj 作为参数。

  • 如果 obj 为空,函数返回一个空对象。

  • 如果 obj 非空,函数遍历 obj 的所有键。

  • 对于每个键,函数将 obj 中的值作为新对象的键,将原始键作为新对象的值。

  • 返回构建完成的新对象,它是 obj 的反转版本。

keys:获取对象中所有的key,包括深层的(表示成a.b的形式)

  1. 使用说明

  • 功能说明:于获取一个对象的所有嵌套属性键的完整路径。这些路径用点号连接,表示从根到叶子的完整路径。

  • 参数:目标对象。

  • 返回值:过滤完后的映射值组成的数组。

  1. 使用代码示例

import { keys } from 'radash'const ra = {name: 'ra',power: 100,friend: {name: 'loki',power: 80},enemies: [{name: 'hathor',power: 12}]
}keys(ra)
// => [
//   'name',
//   'power',
//   'friend.name',
//   'friend.power',
//   'enemies.0.name',
//   'enemies.0.power'
// ]

  1. 源码解析

// 定义一个泛型函数 `keys`。
export const keys = <TValue extends object>(value: TValue): string[] => {// 如果 `value` 为空,则返回一个空数组。if (!value) return []// 定义一个递归函数 `getKeys`,用于遍历嵌套对象或数组并获取所有键的路径。const getKeys = (nested: any, paths: string[]): string[] => {// 如果当前值 `nested` 是一个对象,递归地遍历它的每一个键值对。if (isObject(nested)) {return Object.entries(nested).flatMap(([k, v]) =>// 对于每一个键值对,将键 `k` 添加到路径数组 `paths` 中,// 并继续递归地遍历值 `v`。getKeys(v, [...paths, k]))}// 如果当前值 `nested` 是一个数组,递归地遍历它的每一个元素。if (isArray(nested)) {return nested.flatMap((item, i) => // 对于每一个元素,将索引 `i` 转换为字符串并添加到路径数组 `paths` 中,// 然后继续递归地遍历元素 `item`。getKeys(item, [...paths, `${i}`]))}// 如果当前值 `nested` 既不是对象也不是数组,说明已经到达叶子节点,// 将路径数组 `paths` 连接成字符串并返回。return [paths.join('.')]}// 使用 `getKeys` 函数从根开始遍历 `value`,并获取所有键的路径。return getKeys(value, [])
}

  • 方法流程说明:

  • keys 函数接受一个对象 value 作为参数。

  • 如果 value 为空,函数返回一个空数组。

  • 如果 value 非空,函数定义了一个递归辅助函数 getKeysgetKeys 函数递归地遍历嵌套对象或数组,收集所有键的路径。

  • 对于嵌套对象,getKeys 遍历每个键值对,并对值递归调用自身。

  • 对于嵌套数组,getKeys 遍历每个元素,并对元素递归调用自身,使用元素索引作为路径的一部分。

  • 当到达叶子节点(即不再是对象或数组)时,getKeys 将收集到的路径数组 paths 连接成字符串并返回。

  • keys 函数返回一个包含所有属性键路径的数组。

listify:把对象的键值对转换成一个由特定结构元素组成的数组

  1. 使用说明

  • 功能说明:用于将一个对象的键值对转换成一个由特定结构元素组成的数组。这个函数接受两个参数:一个对象 obj 和一个转换函数 toItemtoItem 函数接受对象的每个键和对应的值,并返回一个新的元素。

  • 参数:目标对象、条件函数。

  • 返回值:构建后的结果数组。

  1. 使用代码示例

import { listify } from 'radash'const fish = {marlin: {weight: 105,},bass: {weight: 8,}
}listify(fish, (key, value) => ({ ...value, name: key })) // => [{ name: 'marlin', weight: 105 }, { name: 'bass', weight: 8 }]

  1. 源码解析

// 定义一个泛型函数 `listify`。
export const listify = <TValue, TKey extends string | number | symbol, KResult>(// 参数 `obj` 是一个对象,其键的类型为 `TKey`,值的类型为 `TValue`。obj: Record<TKey, TValue>,// 参数 `toItem` 是一个函数,它接受一个键和一个值,并返回一个新的结果类型 `KResult` 的元素。toItem: (key: TKey, value: TValue) => KResult
) => {// 如果 `obj` 为空,则返回一个空数组。if (!obj) return []// 使用 `Object.entries` 获取 `obj` 的所有键值对。const entries = Object.entries(obj)// 如果 `obj` 没有键值对,返回一个空数组。if (entries.length === 0) return []// 使用 `reduce` 方法遍历所有键值对,构建结果数组。return entries.reduce((acc, entry) => {// 对每个键值对,调用 `toItem` 函数,并将返回的元素添加到累加器数组 `acc` 中。acc.push(toItem(entry[0] as TKey, entry[1] as TValue))// 返回累加器 `acc`。return acc}, [] as KResult[]) // 初始累加器是一个空数组,其元素类型为 `KResult`。
}

  • 方法流程说明:

  • listify 函数接受一个对象 obj 和一个转换函数 toItem 作为参数。

  • 如果 obj 为空,函数返回一个空数组。

  • 如果 obj 非空,函数使用 Object.entries 获取 obj 的所有键值对。

  • 如果 obj 没有键值对,函数返回一个空数组。

  • 如果 obj 有键值对,函数使用 reduce 方法遍历键值对数组。

  • 对于每个键值对,函数调用 toItem 函数,传入键和值,并将返回的新元素添加到累加器数组中。

  • 返回构建完成的结果数组。

lowerize:将对象的所有key转换为小写形式

  1. 使用说明

  • 功能说明:用于将一个对象的所有键转换为小写形式,内部用到mapKeys,而 mapKeys 函数则用于一般性地将一个对象的键通过一个映射函数转换为新的键。

  • 参数:对象、映射函数。

  • 返回值:返回一个键是小写形式的对象。

  1. 使用代码示例

import { lowerize } from 'radash'const ra = {Mode: 'god',Power: 'sun'
}lowerize(ra) // => { mode, power }

  1. 源码解析

// 定义一个泛型函数 `lowerize`。
export const lowerize = <T extends Record<string, any>>(obj: T) =>// 调用 `mapKeys` 函数将 `obj` 的所有键转换为小写。mapKeys(obj, k => k.toLowerCase()) as LowercasedKeys<T>// `LowercasedKeys<T>` 是一个类型,表示将 `T` 的键转换为小写后的新类型。// 定义一个泛型函数 `mapKeys`。
export const mapKeys = <// `TValue` 表示对象的值的类型。TValue,// `TKey` 表示对象原始键的类型。TKey extends string | number | symbol,// `TNewKey` 表示映射后的新键的类型。TNewKey extends string | number | symbol
>(// `obj` 是一个对象,其键的类型为 `TKey`,值的类型为 `TValue`。obj: Record<TKey, TValue>,// `mapFunc` 是一个映射函数,它接受一个键和一个值,并返回一个新的键。mapFunc: (key: TKey, value: TValue) => TNewKey
): Record<TNewKey, TValue> => {// 使用 `Object.keys` 获取 `obj` 的所有键,并断言键的类型为 `TKey`。const keys = Object.keys(obj) as TKey[]// 使用 `reduce` 方法遍历所有键,创建一个新对象,其键为 `mapFunc` 函数的返回值,值为 `obj` 的值。return keys.reduce((acc, key) => {// 调用 `mapFunc` 函数获取新键,并将 `obj` 中的值赋给新键。acc[mapFunc(key as TKey, obj[key])] = obj[key]// 返回累加器 `acc`,它是正在构建的新对象。return acc}, {} as Record<TNewKey, TValue>) // 初始累加器是一个空对象,类型为 `Record<TNewKey, TValue>`。
}

  • 方法流程说明:

  • lowerize 函数接受一个对象 obj 作为参数。

  • 它调用 mapKeys 函数,传入 obj 和一个将键转换为小写的函数。

  • mapKeys 函数遍历 obj 的所有键,并将每个键转换为小写。

  • mapKeys 返回一个新对象,这个对象的键是小写形式,值与原始对象 obj 相同。

  • lowerize 函数返回这个新对象,并使用 LowercasedKeys<T> 类型断言来指明返回值的类型。

upperize:将对象的所有key转换为大写形式

  1. 使用说明

  • 功能说明:用于将一个对象的所有键转换为大写形式,而 mapKeys 函数则用于一般性地将一个对象的键通过一个映射函数 mapFunc 转换为新的键。

  • 参数:目标对象、映射函数。

  • 返回值:转换后的新对象。

  1. 使用代码示例

import { upperize } from 'radash'const ra = {Mode: 'god',Power: 'sun'
}upperize(ra) // => { MODE, POWER }

  1. 源码解析

// 定义一个泛型函数 `upperize`。
export const upperize = <T extends Record<string, any>>(obj: T) =>// 调用 `mapKeys` 函数将 `obj` 的所有键转换为大写。mapKeys(obj, k => k.toUpperCase()) as UppercasedKeys<T>// `UppercasedKeys<T>` 是一个类型,表示将 `T` 的键转换为大写后的新类型。// 定义一个泛型函数 `mapKeys`。
export const mapKeys = <// `TValue` 表示对象的值的类型。TValue,// `TKey` 表示原始对象的键的类型。TKey extends string | number | symbol,// `TNewKey` 表示映射后的新键的类型。TNewKey extends string | number | symbol
>(// `obj` 是一个对象,其键的类型为 `TKey`,值的类型为 `TValue`。obj: Record<TKey, TValue>,// `mapFunc` 是一个映射函数,它接受一个键和一个值,并返回一个新的键。mapFunc: (key: TKey, value: TValue) => TNewKey
): Record<TNewKey, TValue> => {// 使用 `Object.keys` 获取 `obj` 的所有键,并断言它们的类型为 `TKey`。const keys = Object.keys(obj) as TKey[]// 使用 `reduce` 方法遍历所有键,创建一个新对象,其键为 `mapFunc` 函数的返回值,值为 `obj` 的值。return keys.reduce((acc, key) => {// 调用 `mapFunc` 函数获取新键,并将 `obj` 中的值赋给新键。acc[mapFunc(key as TKey, obj[key])] = obj[key]// 返回累加器 `acc`,它是正在构建的新对象。return acc}, {} as Record<TNewKey, TValue>) // 初始累加器是一个空对象,类型为 `Record<TNewKey, TValue>`。
}

  • 方法流程说明:

  • upperize 函数接受一个对象 obj 作为参数。

  • 它调用 mapKeys 函数,传入 obj 和一个将键转换为大写的函数。

  • mapKeys 函数遍历 obj 的所有键,并将每个键转换为大写。

  • mapKeys 返回一个新对象,这个对象的键是大写形式,值与原始对象 obj 相同。

  • upperize 函数返回这个新对象,并使用 UppercasedKeys<T> 类型断言来指明返回值的类型。

mapEntries:将对象的键值对通过一个转换函数映射为新的对象

  1. 使用说明

  • 功能说明:用于将一个对象的键值对通过一个转换函数 toEntry 映射为新的键值对,并创建一个新的对象。这个函数接受两个参数:一个对象 obj 和一个转换函数 toEntrytoEntry 函数接受对象的每个键和对应的值,并返回一个包含新键和新值的元组。

  • 参数:目标对象、转换函数。

  • 返回值:构建完成的结果对象。

  1. 使用代码示例

import { mapEntries } from 'radash'const ra = {name: 'Ra',power: 'sun',rank: 100,culture: 'egypt'
}mapEntries(ra, (key, value) => [key.toUpperCase(), `${value}`]) // => { NAME: 'Ra', POWER: 'sun', RANK: '100', CULTURE: 'egypt' }

  1. 源码解析

// 定义一个泛型函数 `mapEntries`。
export const mapEntries = <// `TKey` 表示原始对象的键的类型。TKey extends string | number | symbol,// `TValue` 表示原始对象的值的类型。TValue,// `TNewKey` 表示新对象的键的类型。TNewKey extends string | number | symbol,// `TNewValue` 表示新对象的值的类型。TNewValue
>(// `obj` 是一个对象,其键的类型为 `TKey`,值的类型为 `TValue`。obj: Record<TKey, TValue>,// `toEntry` 是一个转换函数,它接受一个键和一个值,并返回一个新的键值对的元组。toEntry: (key: TKey, value: TValue) => [TNewKey, TNewValue]
): Record<TNewKey, TNewValue> => {// 如果 `obj` 为空,则返回一个空对象。if (!obj) return {} as Record<TNewKey, TNewValue>// 使用 `Object.entries` 获取 `obj` 的所有键值对,并使用 `reduce` 方法来构建新对象。return Object.entries(obj).reduce((acc, [key, value]) => {// 对每个键值对,调用 `toEntry` 函数,并获取新键 `newKey` 和新值 `newValue`。const [newKey, newValue] = toEntry(key as TKey, value as TValue)// 将新键值对添加到累加器对象 `acc` 中。acc[newKey] = newValue// 返回累加器 `acc`。return acc}, {} as Record<TNewKey, TNewValue>) // 初始累加器是一个空对象,类型为 `Record<TNewKey, TNewValue>`。
}

  • 方法流程说明:

  • mapEntries 函数接受一个对象 obj 和一个转换函数 toEntry 作为参数。

  • 如果 obj 为空,函数返回一个空对象。

  • 如果 obj 非空,函数使用 Object.entries 获取 obj 的所有键值对。

  • 函数使用 reduce 方法遍历键值对数组。

  • 对于每个键值对,函数调用 toEntry 函数,传入键和值,并将返回的新键值对添加到累加器数组中。

  • 返回构建完成的结果对象。

mapKeys:把对象的kye通过一个映射函数转换为新的key

  1. 使用说明

  • 功能说明:将一个对象的键通过一个映射函数 mapFunc 转换为新的键,并创建一个新对象。这个函数接受两个参数:一个对象 obj 和一个映射函数 mapFuncmapFunc 函数接受对象的每个键和对应的值,并返回一个新的键。

  • 参数:目标对象、映射函数。

  • 返回值:构建完成的新对象。

  1. 使用代码示例

import { mapKeys } from 'radash'const ra = {mode: 'god',power: 'sun'
}mapKeys(ra, key => key.toUpperCase()) // => { MODE, POWER }
mapKeys(ra, (key, value) => value) // => { god: 'god', power: 'power' }

  1. 源码解析

// 定义一个泛型函数 `mapKeys`。
export const mapKeys = <// `TValue` 表示对象的值的类型。TValue,// `TKey` 表示原始对象的键的类型。TKey extends string | number | symbol,// `TNewKey` 表示映射后的新键的类型。TNewKey extends string | number | symbol
>(// `obj` 是一个对象,其键的类型为 `TKey`,值的类型为 `TValue`。obj: Record<TKey, TValue>,// `mapFunc` 是一个映射函数,它接受一个键和一个值,并返回一个新的键。mapFunc: (key: TKey, value: TValue) => TNewKey
): Record<TNewKey, TValue> => {// 使用 `Object.keys` 获取 `obj` 的所有键,并断言它们的类型为 `TKey`。const keys = Object.keys(obj) as TKey[]// 使用 `reduce` 方法遍历所有键,创建一个新对象,其键为 `mapFunc` 函数的返回值,值为 `obj` 的值。return keys.reduce((acc, key) => {// 调用 `mapFunc` 函数获取新键,并将 `obj` 中的值赋给新键。acc[mapFunc(key as TKey, obj[key])] = obj[key]// 返回累加器 `acc`,它是正在构建的新对象。return acc}, {} as Record<TNewKey, TValue>) // 初始累加器是一个空对象,类型为 `Record<TNewKey, TValue>`。
}

方法流程说明:

mapKeys 函数接受一个对象 obj 和一个映射函数 mapFunc 作为参数。

函数使用 Object.keys 获取 obj 的所有键。

函数使用 reduce 方法遍历键数组。

对于每个键,函数调用 mapFunc 函数,传入键和值,并将返回的新键作为新对象的键。

新对象的值与原始对象 obj 中的值相同。

返回构建完成的新对象。

mapValues:对象的value通过一个映射函数转换为新的value

  1. 使用说明

  • 功能说明:将一个对象的值通过一个映射函数 mapFunc 转换为新的值,并创建一个新对象。这个函数接受两个参数:一个对象 obj 和一个映射函数 mapFuncmapFunc 函数接受对象的每个值和对应的键,并返回一个新的值。

  • 参数:目标对象、映射函数。

  • 返回值:构建完成的新对象。

  1. 使用代码示例

import { clone } from 'radash'const ra = {name: 'Ra',power: 100
}const gods = [ra]clone(ra) // => copy of ra
clone(gods) // => copy of gods

  1. 源码解析

// 定义一个泛型函数 `mapValues`。
export const mapValues = <// `TValue` 表示原始对象的值的类型。TValue,// `TKey` 表示对象键的类型。TKey extends string | number | symbol,// `TNewValue` 表示映射后的新值的类型。TNewValue
>(// `obj` 是一个对象,其键的类型为 `TKey`,值的类型为 `TValue`。obj: Record<TKey, TValue>,// `mapFunc` 是一个映射函数,它接受一个值和一个键,并返回一个新的值。mapFunc: (value: TValue, key: TKey) => TNewValue
): Record<TKey, TNewValue> => {// 使用 `Object.keys` 获取 `obj` 的所有键,并断言它们的类型为 `TKey`。const keys = Object.keys(obj) as TKey[]// 使用 `reduce` 方法遍历所有键,创建一个新对象,其键与 `obj` 相同,值为 `mapFunc` 函数的返回值。return keys.reduce((acc, key) => {// 调用 `mapFunc` 函数获取新值,并将其赋给新对象 `acc` 的同名键。acc[key] = mapFunc(obj[key], key)// 返回累加器 `acc`,它是正在构建的新对象。return acc}, {} as Record<TKey, TNewValue>) // 初始累加器是一个空对象,类型为 `Record<TKey, TNewValue>`。
}

方法流程说明:

mapValues 函数接受一个对象 obj 和一个映射函数 mapFunc 作为参数。

函数使用 Object.keys 获取 obj 的所有键。

函数使用 reduce 方法遍历键数组。

对于每个键,函数调用 mapFunc 函数,传入值和键,并将返回的新值作为新对象的值。

新对象的键与原始对象 obj 中的键相同。

返回构建完成的新对象。

omit:创建一个省略了 keys 数组中指定的一些键的新对象

  1. 使用说明

  • 功能说明:创建一个新的对象,该对象是原始对象 obj 的副本,但省略了 keys 数组中指定的一些键。这个函数接受两个参数:一个对象 obj 和一个包含要省略键名的数组 keys

  • 参数:目标对象、要省略的key数组。

  • 返回值:省略了指定键的新对象。

  1. 使用代码示例

import { omit } from 'radash'const fish = {name: 'Bass',weight: 8,source: 'lake',brackish: false
}omit(fish, ['name', 'source']) // => { weight, brackish }

  1. 源码解析

// 定义一个泛型函数 `omit`。
export const omit = <T, TKeys extends keyof T>(// `obj` 是一个对象,其类型为泛型 `T`。obj: T,// `keys` 是一个数组,包含对象 `obj` 中要省略的键名,键名的类型为 `TKeys`。keys: TKeys[]
): Omit<T, TKeys> => {// 如果 `obj` 为空,则返回一个空对象。if (!obj) return {} as Omit<T, TKeys>// 如果 `keys` 为空或长度为0,则返回原始对象 `obj`。if (!keys || keys.length === 0) return obj as Omit<T, TKeys>// 使用 `reduce` 方法遍历 `keys` 数组,从 `obj` 中省略指定的键。return keys.reduce((acc, key) => {// 在这个较为局限的上下文中,允许直接在累加器对象 `acc` 上使用 `delete` 操作符。// 这是出于性能考虑,通常不建议在其他地方使用这种模式。delete acc[key]// 返回更新后的累加器 `acc`。return acc},// 使用对象展开运算符 `{ ...obj }` 创建 `obj` 的浅拷贝,以避免直接修改原始对象。{ ...obj })
}

方法流程说明:

omit 函数接受一个对象 obj 和一个键名数组 keys 作为参数。

如果 obj 为空,函数返回一个空对象。

如果 keys 为空或长度为0,函数返回原始对象 obj

如果 keys 非空,函数使用 reduce 方法遍历 keys 数组。

对于每个键名 key,函数使用 delete 操作符将其从累加器对象 acc 中删除。

函数返回省略了指定键的新对象。

pick:创建一个只包含原始对象中指定的 keys`的对象

  1. 使用说明

  • 功能说明:创建一个新的对象,该对象只包含原始对象 obj 中指定的 keys。这个函数接受两个参数:一个对象 obj 和一个包含要选择键名的数组 keys

  • 参数:目标对象、需要包含的key的数组

  • 返回值:过滤完后的映射值组成的数组。

  1. 使用代码示例

import { pick } from 'radash'const fish = {name: 'Bass',weight: 8,source: 'lake',barckish: false
}pick(fish, ['name', 'source']) // => { name, source }

  1. 源码解析

// 定义一个泛型函数 `pick`。
export const pick = <T extends object, TKeys extends keyof T>(// `obj` 是一个对象,其类型为泛型 `T`。obj: T,// `keys` 是一个数组,包含对象 `obj` 中要选择的键名,键名的类型为 `TKeys`。keys: TKeys[]
): Pick<T, TKeys> => {// 如果 `obj` 为空,则返回一个空对象。if (!obj) return {} as Pick<T, TKeys>// 使用 `reduce` 方法遍历 `keys` 数组,从 `obj` 中选择指定的键。return keys.reduce((acc, key) => {// 检查 `obj` 是否自身拥有属性 `key`(不是从原型链继承来的)。if (Object.prototype.hasOwnProperty.call(obj, key)) // 如果 `obj` 拥有 `key`,则将其添加到累加器对象 `acc` 中。acc[key] = obj[key]// 返回累加器 `acc`。return acc}, {} as Pick<T, TKeys>) // 初始累加器是一个空对象,类型为 `Pick<T, TKeys>`。
}

  • 方法流程说明:

  • pick 函数接受一个对象 obj 和一个键名数组 keys 作为参数。

  • 如果 obj 为空,函数返回一个空对象。

  • 如果 obj 非空,函数使用 reduce 方法遍历 keys 数组。

  • 对于每个键名 key,函数检查 obj 是否自身拥有这个属性(而不是从原型链继承的)。

  • 如果 obj 自身拥有这个属性,函数将这个属性及其值添加到累加器对象 acc 中。

  • 函数返回包含所选键的新对象。

set:在一个对象中设置一个由点或方括号表示法指定的路径上的值

  1. 使用说明

功能说明:用于在一个对象中设置一个值,该值位于由点或方括号表示法指定的路径上。如果路径中的任何中间对象不存在,set 函数将创建它们。

参数:初始对象、属性路径字符串、设置值。

  1. 使用代码示例

import { set } from 'radash'set({}, 'name', 'ra')
// => { name: 'ra' }set({}, 'cards[0].value', 2)
// => { cards: [{ value: 2 }] }

  1. 源码解析

// 定义一个泛型函数 `set`。
export const set = <T extends object, K>(// `initial` 是初始对象,我们将在其中设置值。initial: T,// `path` 是一个字符串,表示要设置值的属性路径。path: string,// `value` 是我们要设置在路径上的值。value: K
): T => {// 如果 `initial` 为空,则返回一个空对象。if (!initial) return {} as T// 如果 `path` 为空或 `value` 未定义,则返回原始对象 `initial`。if (!path || value === undefined) return initial// 使用正则表达式分割路径字符串,得到一个属性名的数组 `segments`。// 过滤掉空字符串,确保所有段都是有效的。const segments = path.split(/[.[]]/g).filter(x => !!x.trim())// 定义一个递归辅助函数 `_set`。const _set = (node: any) => {// 如果路径 `segments` 有多个段,我们需要深入嵌套结构。if (segments.length > 1) {// 弹出当前段的键名 `key`。const key = segments.shift() as string// 检查下一个段是否表示数组索引。const nextIsNum = toInt(segments[0], null) === null ? false : true// 如果当前键不存在,创建一个新的对象或数组,取决于下一个段是否是数字。node[key] = node[key] === undefined ? (nextIsNum ? [] : {}) : node[key]// 递归调用 `_set` 函数,继续设置值。_set(node[key])} else {// 如果路径 `segments` 只有一个段,直接在当前节点上设置值。node[segments[0]] = value}}// ...(函数的其余部分)
}

  • 方法流程说明:

  • set 函数接受一个对象 initial,一个路径字符串 path,和一个值 value 作为参数。

  • 如果 initial 为空,函数返回一个空对象。

  • 如果 path 为空或 value 未定义,函数返回原始对象 initial

  • 函数使用正则表达式分割 path 字符串,得到一个表示属性链的数组 segments

  • 函数定义了一个递归辅助函数 _set,它负责沿着 segments 的路径设置值。

  • 如果 segments 数组有多个元素,函数递归地创建或获取中间对象,并继续沿着路径设置值。

  • 如果 segments 数组只有一个元素,函数在当前的节点上设置值。

  • _set 函数从根对象 initial 开始递归设置值。

shake:过滤对象

  1. 使用说明

  • 功能说明:创建一个新的对象,该对象是原始对象 obj 的副本,但省略了那些经过 filter 函数检查并返回 true 的属性。filter 函数默认会过滤掉值为 undefined 的属性。

  • 参数:目标对象、[过滤函数]。

  • 返回值:过滤完后的映射值组成的数组。

  1. 使用代码示例

import { shake } from 'radash'const ra = {mode: 'god',greek: false,limit: undefined
}shake(ra) // => { mode, greek }
shake(ra, a => !a) // => { mode }

  1. 源码解析

// 定义一个泛型函数 `shake`。
export const shake = <RemovedKeys extends string, T>(// 参数 `obj` 是一个对象,其类型为泛型 `T`。obj: T,// 参数 `filter` 是一个可选的函数,用于决定哪些属性应该被省略。// 默认情况下,它会过滤掉值为 `undefined` 的属性。filter: (value: any) => boolean = x => x === undefined
): Omit<T, RemovedKeys> => {// 如果 `obj` 为空,则返回一个空对象。// 这里返回的类型应该是 `Omit<T, RemovedKeys>` 而不是 `T`。if (!obj) return {} as Omit<T, RemovedKeys>// 使用 `Object.keys` 获取 `obj` 的所有键,并将其类型断言为 `T` 的键的类型数组。const keys = Object.keys(obj) as (keyof T)[]// 使用 `reduce` 方法遍历所有键,创建一个新对象。return keys.reduce((acc, key) => {// 如果 `filter` 函数对当前键的值返回 `true`,则省略该属性。if (filter(obj[key])) {return acc} else {// 否则,将属性添加到累加器对象 `acc` 中。acc[key] = obj[key]return acc}}, {} as Omit<T, RemovedKeys>) // 初始累加器是一个空对象,类型为 `Omit<T, RemovedKeys>`。
}

  • 方法流程说明:

  • shake 函数接受一个对象 obj 和一个可选的过滤函数 filter 作为参数。

  • 如果 obj 为空,函数返回一个空对象。

  • 如果 obj 非空,函数使用 Object.keys 获取 obj 的所有键。

  • 函数使用 reduce 方法遍历键数组。

  • 对于每个键,函数使用 filter 函数检查对应的值,以确定是否应该省略该属性。

  • 如果 filter 函数返回 false,函数将该属性及其值添加到累加器对象 acc 中。

  • 返回包含所选属性的新对象。

文章转载自:雾散声声慢

原文链接:https://www.cnblogs.com/muqiqiang/p/18211285

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

这篇关于lodash已死?radash库方法介绍及源码解析 —— 对象方法篇的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1003400

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

浅谈主机加固,六种有效的主机加固方法

在数字化时代,数据的价值不言而喻,但随之而来的安全威胁也日益严峻。从勒索病毒到内部泄露,企业的数据安全面临着前所未有的挑战。为了应对这些挑战,一种全新的主机加固解决方案应运而生。 MCK主机加固解决方案,采用先进的安全容器中间件技术,构建起一套内核级的纵深立体防护体系。这一体系突破了传统安全防护的局限,即使在管理员权限被恶意利用的情况下,也能确保服务器的安全稳定运行。 普适主机加固措施:

webm怎么转换成mp4?这几种方法超多人在用!

webm怎么转换成mp4?WebM作为一种新兴的视频编码格式,近年来逐渐进入大众视野,其背后承载着诸多优势,但同时也伴随着不容忽视的局限性,首要挑战在于其兼容性边界,尽管WebM已广泛适应于众多网站与软件平台,但在特定应用环境或老旧设备上,其兼容难题依旧凸显,为用户体验带来不便,再者,WebM格式的非普适性也体现在编辑流程上,由于它并非行业内的通用标准,编辑过程中可能会遭遇格式不兼容的障碍,导致操

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}