写在前面
- 主页有更多其他篇章的方法,欢迎访问查看。
- 本篇我们介绍
radash
中对象相关方法的使用和源码解析。
assign:递归合并两个对象
- 使用说明
- 功能说明:类似于 JavaScript 的
Object.assign
方法,用于将override
对象的属性和值复制到initial
对象中。如果属性值是对象,则递归地进行赋值。 - 参数:初始对象、覆盖对象。
- 返回值:返回合并后的新对象
- 功能说明:类似于 JavaScript 的
- 使用代码示例
import { assign } from 'radash' const ra = { name: 'Ra', power: 100 } assign(ra, { name: 'Loki' }) // => { name: Loki, power: 100 }
- 源码解析
// 定义一个泛型函数 `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:浅拷贝对象
- 使用说明
- 功能说明:这个函数接受一个对象
obj
作为参数,并返回这个对象的一个新的浅拷贝。 - 参数:需要克隆的对象。
- 返回值:过滤完后的映射值组成的数组。
- 功能说明:这个函数接受一个对象
- 使用代码示例
import { clone } from 'radash' const ra = { name: 'Ra', power: 100 } const gods = [ra] clone(ra) // => copy of ra clone(gods) // => copy of gods
- 源码解析
// 定义一个泛型函数 `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:把扁平对象构建为深层对象(多维)
- 使用说明
- 功能说明:这个函数接受一个对象
obj
作为参数,并返回这个对象的一个新的浅拷贝。 - 参数:键值对对象。
- 返回值:构建后的新对象。
- 功能说明:这个函数接受一个对象
- 使用代码示例
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 // } // ] // }
- 源码解析
// 定义一个泛型函数 `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的相反操作)
- 使用说明
- 功能说明:这个函数接受一个对象
obj
作为参数,并返回这个对象的一个新的浅拷贝。 - 参数:对象。
- 返回值:构建后的扁平数组。
- 功能说明:这个函数接受一个对象
- 使用代码示例
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 // }
- 源码解析
// 定义一个泛型函数 `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:获取对象中的任意属性,可以通过 .
的方式获取深层的属性
- 使用说明
- 功能说明:用于安全地访问嵌套对象的属性,即使某些中间属性不存在也不会抛出错误。如果找不到指定的路径,则返回一个默认值。
- 参数:目标对象、属性字符(可以
.
表示深层次属性)、默认值。 - 返回值:找到则返回指定值,否则返回默认值。
- 使用代码示例
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'
- 源码解析
// 定义一个泛型函数 `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:把对象中的key
和value
对调
- 使用说明
- 功能说明:用于反转对象的键和值。这意味着原始对象的键成为新对象的值,原始对象的值成为新对象的键。
- 参数:需要反转的对象。
- 返回值:反转后的新数组。
- 使用代码示例
import { invert } from 'radash' const powersByGod = { ra: 'sun', loki: 'tricks', zeus: 'lighning' } invert(gods) // => { sun: ra, tricks: loki, lightning: zeus }
- 源码解析
// 定义一个泛型函数 `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的形式)
- 使用说明
- 功能说明:于获取一个对象的所有嵌套属性键的完整路径。这些路径用点号连接,表示从根到叶子的完整路径。
- 参数:目标对象。
- 返回值:过滤完后的映射值组成的数组。
- 使用代码示例
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' // ]
- 源码解析
// 定义一个泛型函数 `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
非空,函数定义了一个递归辅助函数getKeys
。 getKeys
函数递归地遍历嵌套对象或数组,收集所有键的路径。- 对于嵌套对象,
getKeys
遍历每个键值对,并对值递归调用自身。 - 对于嵌套数组,
getKeys
遍历每个元素,并对元素递归调用自身,使用元素索引作为路径的一部分。 - 当到达叶子节点(即不再是对象或数组)时,
getKeys
将收集到的路径数组paths
连接成字符串并返回。 keys
函数返回一个包含所有属性键路径的数组。
- 方法流程说明:
listify:把对象的键值对转换成一个由特定结构元素组成的数组
- 使用说明
- 功能说明:用于将一个对象的键值对转换成一个由特定结构元素组成的数组。这个函数接受两个参数:一个对象
obj
和一个转换函数toItem
。toItem
函数接受对象的每个键和对应的值,并返回一个新的元素。 - 参数:目标对象、条件函数。
- 返回值:构建后的结果数组。
- 功能说明:用于将一个对象的键值对转换成一个由特定结构元素组成的数组。这个函数接受两个参数:一个对象
- 使用代码示例
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 }]
- 源码解析
// 定义一个泛型函数 `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
转换为小写形式
- 使用说明
- 功能说明:用于将一个对象的所有键转换为小写形式,内部用到
mapKeys
,而mapKeys
函数则用于一般性地将一个对象的键通过一个映射函数转换为新的键。 - 参数:对象、映射函数。
- 返回值:返回一个键是小写形式的对象。
- 功能说明:用于将一个对象的所有键转换为小写形式,内部用到
- 使用代码示例
import { lowerize } from 'radash' const ra = { Mode: 'god', Power: 'sun' } lowerize(ra) // => { mode, power }
- 源码解析
// 定义一个泛型函数 `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
转换为大写形式
- 使用说明
- 功能说明:用于将一个对象的所有键转换为大写形式,而
mapKeys
函数则用于一般性地将一个对象的键通过一个映射函数mapFunc
转换为新的键。 - 参数:目标对象、映射函数。
- 返回值:转换后的新对象。
- 功能说明:用于将一个对象的所有键转换为大写形式,而
- 使用代码示例
import { upperize } from 'radash' const ra = { Mode: 'god', Power: 'sun' } upperize(ra) // => { MODE, POWER }
- 源码解析
// 定义一个泛型函数 `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:将对象的键值对通过一个转换函数映射为新的对象
- 使用说明
- 功能说明:用于将一个对象的键值对通过一个转换函数
toEntry
映射为新的键值对,并创建一个新的对象。这个函数接受两个参数:一个对象obj
和一个转换函数toEntry
。toEntry
函数接受对象的每个键和对应的值,并返回一个包含新键和新值的元组。 - 参数:目标对象、转换函数。
- 返回值:构建完成的结果对象。
- 功能说明:用于将一个对象的键值对通过一个转换函数
- 使用代码示例
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' }
- 源码解析
// 定义一个泛型函数 `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
- 使用说明
- 功能说明:将一个对象的键通过一个映射函数
mapFunc
转换为新的键,并创建一个新对象。这个函数接受两个参数:一个对象obj
和一个映射函数mapFunc
。mapFunc
函数接受对象的每个键和对应的值,并返回一个新的键。 - 参数:目标对象、映射函数。
- 返回值:构建完成的新对象。
- 功能说明:将一个对象的键通过一个映射函数
- 使用代码示例
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' }
- 源码解析
// 定义一个泛型函数 `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
- 使用说明
- 功能说明:将一个对象的值通过一个映射函数
mapFunc
转换为新的值,并创建一个新对象。这个函数接受两个参数:一个对象obj
和一个映射函数mapFunc
。mapFunc
函数接受对象的每个值和对应的键,并返回一个新的值。 - 参数:目标对象、映射函数。
- 返回值:构建完成的新对象。
- 功能说明:将一个对象的值通过一个映射函数
- 使用代码示例
import { clone } from 'radash' const ra = { name: 'Ra', power: 100 } const gods = [ra] clone(ra) // => copy of ra clone(gods) // => copy of gods
- 源码解析
// 定义一个泛型函数 `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
数组中指定的一些键的新对象
- 使用说明
- 功能说明:创建一个新的对象,该对象是原始对象
obj
的副本,但省略了keys
数组中指定的一些键。这个函数接受两个参数:一个对象obj
和一个包含要省略键名的数组keys
。 - 参数:目标对象、要省略的
key
数组。 - 返回值:省略了指定键的新对象。
- 功能说明:创建一个新的对象,该对象是原始对象
- 使用代码示例
import { omit } from 'radash' const fish = { name: 'Bass', weight: 8, source: 'lake', brackish: false } omit(fish, ['name', 'source']) // => { weight, brackish }
- 源码解析
// 定义一个泛型函数 `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`的对象
- 使用说明
- 功能说明:创建一个新的对象,该对象只包含原始对象
obj
中指定的keys
。这个函数接受两个参数:一个对象obj
和一个包含要选择键名的数组keys
。 - 参数:目标对象、需要包含的
key
的数组 - 返回值:过滤完后的映射值组成的数组。
- 功能说明:创建一个新的对象,该对象只包含原始对象
- 使用代码示例
import { pick } from 'radash' const fish = { name: 'Bass', weight: 8, source: 'lake', barckish: false } pick(fish, ['name', 'source']) // => { name, source }
- 源码解析
// 定义一个泛型函数 `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:在一个对象中设置一个由点或方括号表示法指定的路径上的值
- 使用说明
- 功能说明:用于在一个对象中设置一个值,该值位于由点或方括号表示法指定的路径上。如果路径中的任何中间对象不存在,
set
函数将创建它们。 - 参数:初始对象、属性路径字符串、设置值。
- 功能说明:用于在一个对象中设置一个值,该值位于由点或方括号表示法指定的路径上。如果路径中的任何中间对象不存在,
- 使用代码示例
import { set } from 'radash' set({}, 'name', 'ra') // => { name: 'ra' } set({}, 'cards[0].value', 2) // => { cards: [{ value: 2 }] }
- 源码解析
// 定义一个泛型函数 `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:过滤对象
- 使用说明
- 功能说明:创建一个新的对象,该对象是原始对象
obj
的副本,但省略了那些经过filter
函数检查并返回true
的属性。filter
函数默认会过滤掉值为undefined
的属性。 - 参数:目标对象、[过滤函数]。
- 返回值:过滤完后的映射值组成的数组。
- 功能说明:创建一个新的对象,该对象是原始对象
- 使用代码示例
import { shake } from 'radash' const ra = { mode: 'god', greek: false, limit: undefined } shake(ra) // => { mode, greek } shake(ra, a => !a) // => { mode }
- 源码解析
// 定义一个泛型函数 `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
中。 - 返回包含所选属性的新对象。
- 方法流程说明:
写在后面
- 我相信能看到最后的都是帅气多金想进步的大漂亮和大帅笔,感谢阅读到这儿!
- 等所有方法更新完毕,作者会整理一份
radash
完整方法目录上传,包括思维导图和使用目录。 - 大家有任何问题或见解,欢迎评论区留言交流和批评指正!!!
- 你的每一个收藏都是作者写作的动力!!!
- 点击访问:radash官网