theme: nico 寫在前面 主頁有更多其他篇章的方法,歡迎訪問查看。 本篇我們介紹radash中對象相關方法的使用和源碼解析。 assign:遞歸合併兩個對象 使用說明 功能說明:類似於 JavaScript 的 Object.assign 方法,用於將 override 對象的屬性和值複製到 ...
寫在前面
- 主頁有更多其他篇章的方法,歡迎訪問查看。
- 本篇我們介紹
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官網