lodash已死?radash庫方法介紹及源碼解析 —— 對象方法篇

来源:https://www.cnblogs.com/muqiqiang/p/18211285
-Advertisement-
Play Games

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


radash.jpg

寫在前面

  • 主頁有更多其他篇章的方法,歡迎訪問查看。
  • 本篇我們介紹radash中對象相關方法的使用和源碼解析。

assign:遞歸合併兩個對象

  1. 使用說明
    • 功能說明:類似於 JavaScript 的 Object.assign 方法,用於將 override 對象的屬性和值複製到 initial 對象中。如果屬性值是對象,則遞歸地進行賦值。
    • 參數:初始對象、覆蓋對象。
    • 返回值:返回合併後的新對象
  2. 使用代碼示例
    import { assign } from 'radash'
    
    const ra = {
      name: 'Ra',
      power: 100
    }
    
    assign(ra, { name: 'Loki' })
    // => { name: Loki, power: 100 }
    
  3. 源碼解析
    // 定義一個泛型函數 `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` 的空對象。
      )
    }
    
    • 方法流程說明:
      1. assign 函數接受兩個參數,initialoverride,它們都是對象。
      2. 如果其中一個對象為空,函數將返回另一個非空對象。如果兩個對象都為空,函數返回一個空對象。
      3. 如果兩個對象都非空,函數使用 Object.entriesreduce 方法遍歷 override 對象的所有屬性。
      4. 對於每個屬性,如果 initial 對象中對應的屬性也是一個對象,則遞歸地調用 assign 函數來合併這兩個對象。
      5. 如果 initial 對象中對應的屬性不是對象,或 override 對象中的屬性在 initial 對象中不存在,則直接使用 override 對象中的值。
      6. 返回合併後的新對象。

clone:淺拷貝對象

  1. 使用說明
    • 功能說明:這個函數接受一個對象 obj 作為參數,並返回這個對象的一個新的淺拷貝。
    • 參數:需要克隆的對象。
    • 返回值:過濾完後的映射值組成的數組。
  2. 使用代碼示例
    import { clone } from 'radash'
    
    const ra = {
      name: 'Ra',
      power: 100
    }
    
    const gods = [ra]
    
    clone(ra) // => copy of ra
    clone(gods) // => copy of gods
    
  3. 源碼解析
    // 定義一個泛型函數 `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
    }
    
    • 方法流程說明:
      1. 如果 obj 是一個原始值,直接返回它,因為原始值在JavaScript中是不可變的。
      2. 如果 obj 是一個函數,使用 bind 方法創建並返回一個新的函數副本。
      3. 如果 obj 是一個對象或數組,使用 obj 的構造函數創建一個新的空對象或空數組 newObj
      4. 遍歷 obj 的自有屬性,並將每個屬性值複製到 newObj 中。
      5. 返回新對象 newObj

construct:把扁平對象構建為深層對象(多維)

  1. 使用說明
    • 功能說明:這個函數接受一個對象 obj 作為參數,並返回這個對象的一個新的淺拷貝。
    • 參數:鍵值對對象。
    • 返回值:構建後的新對象。
  2. 使用代碼示例
    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
    //     }
    //   ]
    // }
    
  3. 源碼解析
    // 定義一個泛型函數 `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` 是一個空對象。
    }
    
    • 方法流程說明:
      1. construct 函數接受一個對象 obj 作為參數。
      2. 如果 obj 為空,函數返回一個空對象。
      3. 如果 obj 非空,函數遍歷 obj 的所有自有屬性。
      4. 對於每個屬性,函數使用 set 函數將 obj 中的屬性值複製到新對象中。
      5. 返回構建完成的新對象。

crush:把深層(多維)對象構建成扁平對象(construct的相反操作)

  1. 使用說明
    • 功能說明:這個函數接受一個對象 obj 作為參數,並返回這個對象的一個新的淺拷貝。
    • 參數:對象。
    • 返回值:構建後的扁平數組。
  2. 使用代碼示例
    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
    // }
    
  3. 源碼解析
    // 定義一個泛型函數 `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)
      )
    }
    
    • 方法流程說明:
      1. crush 函數接受一個對象 value 作為參數。
      2. 如果 value 為空,函數返回一個空對象。
      3. 如果 value 非空,函數使用 keys 函數獲取 value 的所有鍵名。
      4. 函數調用 objectify,傳入鍵名數組、鍵生成函數(這裡是標識函數 k => k)和值生成函數(通過調用 get(value, k) 獲取每個鍵的值)。
      5. objectify 函數返回一個新對象,這個對象的屬性和值與 value 相同。

get:獲取對象中的任意屬性,可以通過 . 的方式獲取深層的屬性

  1. 使用說明
    • 功能說明:用於安全地訪問嵌套對象的屬性,即使某些中間屬性不存在也不會拋出錯誤。如果找不到指定的路徑,則返回一個預設值。
    • 參數:目標對象、屬性字元(可以.表示深層次屬性)、預設值。
    • 返回值:找到則返回指定值,否則返回預設值。
  2. 使用代碼示例
    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'
    
  3. 源碼解析
    // 定義一個泛型函數 `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
    }
    
    • 方法流程說明:
      1. get 函數接受一個對象 value,一個表示屬性路徑的字元串 path,以及一個可選的預設值 defaultValue
      2. 使用正則表達式分割 path 字元串,得到一個表示屬性鏈的數組 segments
      3. 遍歷 segments 數組,依次訪問每個屬性。
      4. 如果在訪問過程中遇到 nullundefined,或者到達路徑的末尾但找不到值,則返回 defaultValue
      5. 如果成功訪問到路徑上的所有屬性,並找到了值,則返回這個值。

invert:把對象中的keyvalue對調

  1. 使用說明
    • 功能說明:用於反轉對象的鍵和值。這意味著原始對象的鍵成為新對象的值,原始對象的值成為新對象的鍵。
    • 參數:需要反轉的對象。
    • 返回值:反轉後的新數組。
  2. 使用代碼示例
    import { invert } from 'radash'
    
    const powersByGod = {
      ra: 'sun',
      loki: 'tricks',
      zeus: 'lighning'
    }
    
    invert(gods) // => { sun: ra, tricks: loki, lightning: zeus }
    
  3. 源碼解析
    // 定義一個泛型函數 `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>`。
    }
    
    • 方法流程說明:
      1. invert 函數接受一個對象 obj 作為參數。
      2. 如果 obj 為空,函數返回一個空對象。
      3. 如果 obj 非空,函數遍歷 obj 的所有鍵。
      4. 對於每個鍵,函數將 obj 中的值作為新對象的鍵,將原始鍵作為新對象的值。
      5. 返回構建完成的新對象,它是 obj 的反轉版本。

keys:獲取對象中所有的key,包括深層的(表示成a.b的形式)

  1. 使用說明
    • 功能說明:於獲取一個對象的所有嵌套屬性鍵的完整路徑。這些路徑用點號連接,表示從根到葉子的完整路徑。
    • 參數:目標對象。
    • 返回值:過濾完後的映射值組成的數組。
  2. 使用代碼示例
    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'
    // ]
    
  3. 源碼解析
    // 定義一個泛型函數 `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, [])
    }
    
    • 方法流程說明:
      1. keys 函數接受一個對象 value 作為參數。
      2. 如果 value 為空,函數返回一個空數組。
      3. 如果 value 非空,函數定義了一個遞歸輔助函數 getKeys
      4. getKeys 函數遞歸地遍歷嵌套對象或數組,收集所有鍵的路徑。
      5. 對於嵌套對象,getKeys 遍歷每個鍵值對,並對值遞歸調用自身。
      6. 對於嵌套數組,getKeys 遍歷每個元素,並對元素遞歸調用自身,使用元素索引作為路徑的一部分。
      7. 當到達葉子節點(即不再是對象或數組)時,getKeys 將收集到的路徑數組 paths 連接成字元串並返回。
      8. keys 函數返回一個包含所有屬性鍵路徑的數組。

listify:把對象的鍵值對轉換成一個由特定結構元素組成的數組

  1. 使用說明
    • 功能說明:用於將一個對象的鍵值對轉換成一個由特定結構元素組成的數組。這個函數接受兩個參數:一個對象 obj 和一個轉換函數 toItemtoItem 函數接受對象的每個鍵和對應的值,並返回一個新的元素。
    • 參數:目標對象、條件函數。
    • 返回值:構建後的結果數組。
  2. 使用代碼示例
    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 }]
    
  3. 源碼解析
    // 定義一個泛型函數 `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`。
    }
    
    • 方法流程說明:
      1. listify 函數接受一個對象 obj 和一個轉換函數 toItem 作為參數。
      2. 如果 obj 為空,函數返回一個空數組。
      3. 如果 obj 非空,函數使用 Object.entries 獲取 obj 的所有鍵值對。
      4. 如果 obj 沒有鍵值對,函數返回一個空數組。
      5. 如果 obj 有鍵值對,函數使用 reduce 方法遍歷鍵值對數組。
      6. 對於每個鍵值對,函數調用 toItem 函數,傳入鍵和值,並將返回的新元素添加到累加器數組中。
      7. 返回構建完成的結果數組。

lowerize:將對象的所有key轉換為小寫形式

  1. 使用說明
    • 功能說明:用於將一個對象的所有鍵轉換為小寫形式,內部用到mapKeys,而 mapKeys 函數則用於一般性地將一個對象的鍵通過一個映射函數轉換為新的鍵。
    • 參數:對象、映射函數。
    • 返回值:返回一個鍵是小寫形式的對象。
  2. 使用代碼示例
    import { lowerize } from 'radash'
    
    const ra = {
      Mode: 'god',
      Power: 'sun'
    }
    
    lowerize(ra) // => { mode, power }
    
  3. 源碼解析
    // 定義一個泛型函數 `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>`。
    }
    
    • 方法流程說明:
      1. lowerize 函數接受一個對象 obj 作為參數。
      2. 它調用 mapKeys 函數,傳入 obj 和一個將鍵轉換為小寫的函數。
      3. mapKeys 函數遍歷 obj 的所有鍵,並將每個鍵轉換為小寫。
      4. mapKeys 返回一個新對象,這個對象的鍵是小寫形式,值與原始對象 obj 相同。
      5. lowerize 函數返回這個新對象,並使用 LowercasedKeys<T> 類型斷言來指明返回值的類型。

upperize:將對象的所有key轉換為大寫形式

  1. 使用說明
    • 功能說明:用於將一個對象的所有鍵轉換為大寫形式,而 mapKeys 函數則用於一般性地將一個對象的鍵通過一個映射函數 mapFunc 轉換為新的鍵。
    • 參數:目標對象、映射函數。
    • 返回值:轉換後的新對象。
  2. 使用代碼示例
    import { upperize } from 'radash'
    
    const ra = {
      Mode: 'god',
      Power: 'sun'
    }
    
    upperize(ra) // => { MODE, POWER }
    
  3. 源碼解析
    // 定義一個泛型函數 `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>`。
    }
    
    • 方法流程說明:
      1. upperize 函數接受一個對象 obj 作為參數。
      2. 它調用 mapKeys 函數,傳入 obj 和一個將鍵轉換為大寫的函數。
      3. mapKeys 函數遍歷 obj 的所有鍵,並將每個鍵轉換為大寫。
      4. mapKeys 返回一個新對象,這個對象的鍵是大寫形式,值與原始對象 obj 相同。
      5. upperize 函數返回這個新對象,並使用 UppercasedKeys<T> 類型斷言來指明返回值的類型。

mapEntries:將對象的鍵值對通過一個轉換函數映射為新的對象

  1. 使用說明
    • 功能說明:用於將一個對象的鍵值對通過一個轉換函數 toEntry 映射為新的鍵值對,並創建一個新的對象。這個函數接受兩個參數:一個對象 obj 和一個轉換函數 toEntrytoEntry 函數接受對象的每個鍵和對應的值,並返回一個包含新鍵和新值的元組。
    • 參數:目標對象、轉換函數。
    • 返回值:構建完成的結果對象。
  2. 使用代碼示例
    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' }
    
  3. 源碼解析
    // 定義一個泛型函數 `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>`。
    }
    
    • 方法流程說明:
      1. mapEntries 函數接受一個對象 obj 和一個轉換函數 toEntry 作為參數。
      2. 如果 obj 為空,函數返回一個空對象。
      3. 如果 obj 非空,函數使用 Object.entries 獲取 obj 的所有鍵值對。
      4. 函數使用 reduce 方法遍歷鍵值對數組。
      5. 對於每個鍵值對,函數調用 toEntry 函數,傳入鍵和值,並將返回的新鍵值對添加到累加器數組中。
      6. 返回構建完成的結果對象。

mapKeys:把對象的kye通過一個映射函數轉換為新的key

  1. 使用說明
    • 功能說明:將一個對象的鍵通過一個映射函數 mapFunc 轉換為新的鍵,並創建一個新對象。這個函數接受兩個參數:一個對象 obj 和一個映射函數 mapFuncmapFunc 函數接受對象的每個鍵和對應的值,並返回一個新的鍵。
    • 參數:目標對象、映射函數。
    • 返回值:構建完成的新對象。
  2. 使用代碼示例
    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' }
    
  3. 源碼解析
    // 定義一個泛型函數 `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>`。
    }
    
    • 方法流程說明:
      1. mapKeys 函數接受一個對象 obj 和一個映射函數 mapFunc 作為參數。
      2. 函數使用 Object.keys 獲取 obj 的所有鍵。
      3. 函數使用 reduce 方法遍歷鍵數組。
      4. 對於每個鍵,函數調用 mapFunc 函數,傳入鍵和值,並將返回的新鍵作為新對象的鍵。
      5. 新對象的值與原始對象 obj 中的值相同。
      6. 返回構建完成的新對象。

mapValues:對象的value通過一個映射函數轉換為新的value

  1. 使用說明
    • 功能說明:將一個對象的值通過一個映射函數 mapFunc 轉換為新的值,並創建一個新對象。這個函數接受兩個參數:一個對象 obj 和一個映射函數 mapFuncmapFunc 函數接受對象的每個值和對應的鍵,並返回一個新的值。
    • 參數:目標對象、映射函數。
    • 返回值:構建完成的新對象。
  2. 使用代碼示例
    import { clone } from 'radash'
    
    const ra = {
      name: 'Ra',
      power: 100
    }
    
    const gods = [ra]
    
    clone(ra) // => copy of ra
    clone(gods) // => copy of gods
    
  3. 源碼解析
    // 定義一個泛型函數 `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>`。
    }
    
    • 方法流程說明:
      1. mapValues 函數接受一個對象 obj 和一個映射函數 mapFunc 作為參數。
      2. 函數使用 Object.keys 獲取 obj 的所有鍵。
      3. 函數使用 reduce 方法遍歷鍵數組。
      4. 對於每個鍵,函數調用 mapFunc 函數,傳入值和鍵,並將返回的新值作為新對象的值。
      5. 新對象的鍵與原始對象 obj 中的鍵相同。
      6. 返回構建完成的新對象。

omit:創建一個省略了 keys 數組中指定的一些鍵的新對象

  1. 使用說明
    • 功能說明:創建一個新的對象,該對象是原始對象 obj 的副本,但省略了 keys 數組中指定的一些鍵。這個函數接受兩個參數:一個對象 obj 和一個包含要省略鍵名的數組 keys
    • 參數:目標對象、要省略的key數組。
    • 返回值:省略了指定鍵的新對象。
  2. 使用代碼示例
    import { omit } from 'radash'
    
    const fish = {
      name: 'Bass',
      weight: 8,
      source: 'lake',
      brackish: false
    }
    
    omit(fish, ['name', 'source']) // => { weight, brackish }
    
  3. 源碼解析
    // 定義一個泛型函數 `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 }
      )
    }
    
    • 方法流程說明:
      1. omit 函數接受一個對象 obj 和一個鍵名數組 keys 作為參數。
      2. 如果 obj 為空,函數返回一個空對象。
      3. 如果 keys 為空或長度為0,函數返回原始對象 obj
      4. 如果 keys 非空,函數使用 reduce 方法遍歷 keys 數組。
      5. 對於每個鍵名 key,函數使用 delete 操作符將其從累加器對象 acc 中刪除。
      6. 函數返回省略了指定鍵的新對象。

pick:創建一個只包含原始對象中指定的 keys`的對象

  1. 使用說明
    • 功能說明:創建一個新的對象,該對象只包含原始對象 obj 中指定的 keys。這個函數接受兩個參數:一個對象 obj 和一個包含要選擇鍵名的數組 keys
    • 參數:目標對象、需要包含的key的數組
    • 返回值:過濾完後的映射值組成的數組。
  2. 使用代碼示例
    import { pick } from 'radash'
    
    const fish = {
      name: 'Bass',
      weight: 8,
      source: 'lake',
      barckish: false
    }
    
    pick(fish, ['name', 'source']) // => { name, source }
    
  3. 源碼解析
    // 定義一個泛型函數 `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>`。
    }
    
    • 方法流程說明:
      1. pick 函數接受一個對象 obj 和一個鍵名數組 keys 作為參數。
      2. 如果 obj 為空,函數返回一個空對象。
      3. 如果 obj 非空,函數使用 reduce 方法遍歷 keys 數組。
      4. 對於每個鍵名 key,函數檢查 obj 是否自身擁有這個屬性(而不是從原型鏈繼承的)。
      5. 如果 obj 自身擁有這個屬性,函數將這個屬性及其值添加到累加器對象 acc 中。
      6. 函數返回包含所選鍵的新對象。

set:在一個對象中設置一個由點或方括弧表示法指定的路徑上的值

  1. 使用說明
    • 功能說明:用於在一個對象中設置一個值,該值位於由點或方括弧表示法指定的路徑上。如果路徑中的任何中間對象不存在,set 函數將創建它們。
    • 參數:初始對象、屬性路徑字元串、設置值。
  2. 使用代碼示例
    import { set } from 'radash'
    
    set({}, 'name', 'ra')
    // => { name: 'ra' }
    
    set({}, 'cards[0].value', 2)
    // => { cards: [{ value: 2 }] }
    
  3. 源碼解析
    // 定義一個泛型函數 `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
        }
      }
      // ...(函數的其餘部分)
    }
    
    • 方法流程說明:
      1. set 函數接受一個對象 initial,一個路徑字元串 path,和一個值 value 作為參數。
      2. 如果 initial 為空,函數返回一個空對象。
      3. 如果 path 為空或 value 未定義,函數返回原始對象 initial
      4. 函數使用正則表達式分割 path 字元串,得到一個表示屬性鏈的數組 segments
      5. 函數定義了一個遞歸輔助函數 _set,它負責沿著 segments 的路徑設置值。
      6. 如果 segments 數組有多個元素,函數遞歸地創建或獲取中間對象,並繼續沿著路徑設置值。
      7. 如果 segments 數組只有一個元素,函數在當前的節點上設置值。
      8. _set 函數從根對象 initial 開始遞歸設置值。

shake:過濾對象

  1. 使用說明
    • 功能說明:創建一個新的對象,該對象是原始對象 obj 的副本,但省略了那些經過 filter 函數檢查並返回 true 的屬性。filter 函數預設會過濾掉值為 undefined 的屬性。
    • 參數:目標對象、[過濾函數]。
    • 返回值:過濾完後的映射值組成的數組。
  2. 使用代碼示例
    import { shake } from 'radash'
    
    const ra = {
      mode: 'god',
      greek: false,
      limit: undefined
    }
    
    shake(ra) // => { mode, greek }
    shake(ra, a => !a) // => { mode }
    
  3. 源碼解析
    // 定義一個泛型函數 `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>`。
    }
    
    • 方法流程說明:
      1. shake 函數接受一個對象 obj 和一個可選的過濾函數 filter 作為參數。
      2. 如果 obj 為空,函數返回一個空對象。
      3. 如果 obj 非空,函數使用 Object.keys 獲取 obj 的所有鍵。
      4. 函數使用 reduce 方法遍歷鍵數組。
      5. 對於每個鍵,函數使用 filter 函數檢查對應的值,以確定是否應該省略該屬性。
      6. 如果 filter 函數返回 false,函數將該屬性及其值添加到累加器對象 acc 中。
      7. 返回包含所選屬性的新對象。

寫在後面

  • 我相信能看到最後的都是帥氣多金想進步的大漂亮和大帥筆,感謝閱讀到這兒!
  • 等所有方法更新完畢,作者會整理一份radash完整方法目錄上傳,包括思維導圖和使用目錄。
  • 大家有任何問題或見解,歡迎評論區留言交流和批評指正!!!
  • 你的每一個收藏都是作者寫作的動力!!!
  • 點擊訪問:radash官網

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Linux不像windows系統那樣方便的圖形界面,特別是作為伺服器使用的時候,只有命令行可以使用。 我有個雲伺服器平時用來做一些數據分享用的,最近想看看磁碟和其中文件的占用情況,於是搜索並學習了一些查看磁碟空間信息的命令,命令雖然簡單,但對我自己來說還是有些新的東西值得記錄。 1. df 首先,登 ...
  • Centos7安裝weblogic 1、配置java環境weblogic運行依賴java環境,所以第一步先配置java環境上傳、解壓jdk安裝包[root@bogon ~]# rz -be[root@bogon ~]# tar -zxvf jdk1.8.tar.gz 配置java環境變數[root@ ...
  • 背景 根據orangepi zero2用戶手冊說明,linux5.13內核不能使用 modprobe fbtft_device 驅動spi lcd 查看linux內核源碼提交記錄,發現在v5.4-rc3中刪除了fbtft_device.c文件 commit如下 staging/fbtft: Remo ...
  • 一、卸載mariadb的rpm包 1、首先,你需要找出已安裝的MariaDB包的具體名稱。可以使用以下命令列出所有已安裝的MariaDB包: rpm -qa | grep mariadb 2、刪除命令(安裝mysql不一定需要卸載)yum -y remove +【上圖的文件名】或者rpm -e -- ...
  • 前言 應用中的信息傳遞是為了實現各種功能和交互。信息傳遞可以幫助用戶和應用之間進行有效的溝通和交流。通過信息傳遞,應用可以向用戶傳遞重要的消息、通知和提示,以提供及時的反饋和指導。同時,用戶也可以通過信息傳遞嚮應用發送指令、請求和反饋,以實現個性化的需求和操作。 信息傳遞還可以幫助應用之間實現數 ...
  • Symbol 引用 iconfont icon圖標庫 Symbol 引用 這是一種全新的使用方式,應該說這才是未來的主流,也是平臺目前推薦的用法。相關介紹可以參考這篇文章 這種用法其實是做了一個 SVG 的集合,與另外兩種相比具有如下特點: 支持多色圖標了,不再受單色限制。 通過一些技巧,支持像字體 ...
  • XML中的字元串數據類型表示字元序列,包括換行、回車和製表符。處理器不修改值。`normalizedString`去除這些特殊字元,`token`則進一步移除前導和尾隨空格及多餘空格。字元串類型可使用枚舉、長度等限制。`date`和`dateTime`數據類型表示日期和時間,`duration`表示... ...
  • 一、是什麼 HMR全稱 Hot Module Replacement,可以理解為模塊熱替換,指在應用程式運行過程中,替換、添加、刪除模塊,而無需重新刷新整個應用 例如,我們在應用運行過程中修改了某個模塊,通過自動刷新會導致整個應用的整體刷新,那頁面中的狀態信息都會丟失 如果使用的是 HMR,就可以實 ...
一周排行
    -Advertisement-
    Play Games
  • 一:背景 1. 講故事 前些天有位朋友找到我,說他們的程式會偶發性的卡死一段時間,然後又好了,讓我幫忙看下怎麼回事?窗體類的程式解決起來相對來說比較簡單,讓朋友用procdump自動抓一個卡死時的dump,拿到dump之後,上 windbg 說話。 二:WinDbg 分析 1. 主線程在做什麼 要想 ...
  • 功能說明 使用ListView時,希望可以在單元格顯示圖片或其他控制項,發現原生的ListView不支持,於是通過拓展,實現ListView可以顯示任意控制項的功能,效果如下: 實現方法 本來想著在單元格裡面實現控制項的自繪的,但是沒找到辦法,最後是通過在單元格的錶面顯示對應控制項的,浮於錶面達到目的。 實 ...
  • 由於.NET Framework 4.0 是比較古老的版本,只有New Relic 7.0以下的版本才會支持.NET Framework 4.0的引用程式。 Technical support for .NET Framework 4.0 or lower 你可以參考這個官方Install New ...
  • 前言 隨著 DEV24.1.3 的發佈,XAF Blazor 中的屬性編輯器(PropertyEditor)也進行了很大的改動,在使用體驗上也更接近 WinForm 了,由於進行了大量的封裝,理解上沒有 WinForm 直觀,所以本文通過對屬性編輯器的原理進行解析,並對比新舊版本中的變化,使大家能夠 ...
  • OPC基金會提供了OPC UA .NET標準庫以及示常式序,但官方文檔過於簡單,光看官方文檔和示常式序很難弄懂OPC UA .NET標準庫怎麼用,花了不少時間摸索才略微弄懂如何使用,以下記錄如何從一個控制台程式開發一個OPC UA伺服器。 安裝Nuget包 安裝OPCFoundation.NetSt ...
  • 今天在技術群里,石頭哥向大家提了個問題:"如何在一個以System身份運行的.NET程式(Windows Services)中,以其它活動的用戶身份啟動可互動式進程(桌面應用程式、控制台程式、等帶有UI和互動式體驗的程式)"? 我以前有過類似的需求,是在GitLab流水線中運行帶有UI的自動化測試程 ...
  • .Net 中提供了一系列的管理對象集合的類型,數組、可變列表、字典等。從類型安全上集合分為兩類,泛型集合 和 非泛型集合,傳統的非泛型集合存儲為Object,需要類型轉。而泛型集合提供了更好的性能、編譯時類型安全,推薦使用。 ...
  • 在以前我做程式的時候,一般在登錄視窗裡面顯示程式名稱,登錄視窗一般設置一張背景圖片,由於程式的名稱一般都是確定的,所以也不存在太大的問題,不過如果客戶定製不同的系統的時候,需要使用Photoshop修改下圖層的文字,再生成圖片,然後替換一下也可以了。不過本著減少客戶使用繁瑣性,也可以使用空白名稱的通... ...
  • 一:背景 1. 講故事 在dump分析的過程中經常會看到很多線程卡在Monitor.Wait方法上,曾經也有不少人問我為什麼用 !syncblk 看不到 Monitor.Wait 上的鎖信息,剛好昨天有時間我就來研究一下。 二:Monitor.Wait 底層怎麼玩的 1. 案例演示 為了方便講述,先 ...
  • 目錄前言學習參考過程總結: 前言 做個自由仔。 學習參考 ChatGpt; https://www.cnblogs.com/zhili/p/DesignPatternSummery.html(大佬的,看了好多次) 過程 原由: 一開始只是想查查鏈式調用原理,以為是要繼承什麼介面,實現什麼方法才可以實 ...