lodash已死?radash庫方法介紹及源碼解析 —— 對象方法篇
寫在前面
- 主頁有更多其他篇章的方法,歡迎訪問查看。
- 本篇我們介紹
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完整方法目錄上傳,包括思維導圖和使用目錄。 - 大家有任何問題或見解,歡迎評論區留言交流和批評指正!??!
- 你的每一個收藏都是作者寫作的動力?。。?/li>
- 點擊訪問:radash官網

前端技術分享,radash庫對象相關方法的使用和源碼解析,封面你們對象,原圖評論獲取
浙公網安備 33010602011771號