文章加密

;

2024年10月24日 星期四

reduce 做資料分組

 告訴我下面這段程式在做什麼? const list =txList.value.reduce((acc, item)=>{ if(!acc[item.txTerm])){ acc[item.txTerm] = [] } acc[item.txTerm].push(item) return acc },{}) ||[]; return list })

ChatGPT 說:
ChatGPT

這段程式碼的主要功能是將 txList.value 中的項目根據 txTerm 屬性進行分組。以下是程式碼的逐步解析:

  1. txList.value.reduce(...): 使用 reduce 方法來遍歷 txList.value 陣列,並將每個項目依據其 txTerm 屬性進行分組。

  2. (acc, item) => {...}: 這是一個回調函數,acc 是累積器,用來保存分組結果,item 是當前正在處理的項目。

  3. if(!acc[item.txTerm]): 檢查累積器 acc 中是否已經存在以 item.txTerm 為鍵的屬性。如果不存在,就創建一個空陣列。

  4. acc[item.txTerm].push(item): 將當前項目 item 添加到相應的 txTerm 鍵的陣列中。

  5. return acc: 返回累積器,繼續下一個項目的處理。

  6. {},: reduce 的初始值設為一個空物件 {}

  7. || []: 如果 reduce 的結果為假值(例如 undefined),則返回一個空陣列。

最後,這段程式碼的結果是將 txList.value 中的項目分組後返回的物件,其中每個 txTerm 對應一個項目陣列。

你說:
可以給個例子嗎
ChatGPT 說:
ChatGPT

當然可以!假設 txList.value 的內容如下:

javascript
const txList = { value: [ { id: 1, txTerm: 'A', amount: 100 }, { id: 2, txTerm: 'B', amount: 200 }, { id: 3, txTerm: 'A', amount: 150 }, { id: 4, txTerm: 'C', amount: 300 }, { id: 5, txTerm: 'B', amount: 250 }, ] };

運行你提供的程式碼後,list 的結果將會是:

javascript
{ A: [ { id: 1, txTerm: 'A', amount: 100 }, { id: 3, txTerm: 'A', amount: 150 } ], B: [ { id: 2, txTerm: 'B', amount: 200 }, { id: 5, txTerm: 'B', amount: 250 } ], C: [ { id: 4, txTerm: 'C', amount: 300 } ] }

在這個結果中,每個 txTerm(A、B、C)對應一個包含相關項目的陣列。這樣就成功地將項目按 txTerm 分組了!

2024年10月14日 星期一

New Words

 InAppBroswer, 前端BFF(Backends For Frontends, 服務於前端的後端), gradle vs Maven

2024年10月3日 星期四

Cookie/ LocalStorage/ SessionStorage 差別

 https://ithelp.ithome.com.tw/articles/10268532

屬性CookielocalStoragesessionStorage
存儲容量較小,約 4KB較大,約 5MB較大,約 5MB
存放位置 瀏覽器 &  Server瀏覽器瀏覽器
持久性可設置過期時間永久性,除非清除瀏覽器資料關閉頁籤/瀏覽器後清空
使用場景身分驗證、追蹤與分析本地設置、離線應用臨時資料儲存、表單數據保留
Server請求時,會夾帶而外資訊,過多請求時,要注意可能產生效能問題資料存於 Client 端,與Server端無關,請求時不影響資料存於 Client 端,與Server端無關,請求時不影響

[TS] any v.s. unknown

unknown

我們不能夠對 unknown 型別的東西進行任何除了讀寫和比較以外的操作

功能一:保證變數的值不會被不小心地操作到

例子:

function compareArrayAtEven(arr1: unknown[], arr2: unknown[]): boolean {
    let diff = arr1.length - arr2.length;
    if(diff > 1 || diff < -1) return false;
    for(let i = 0; i < arr1.length && i < arr2.length; i++) {
        if(arr1[i] !== arr2[i] + 2) return false; // TypeScript 會在這邊報錯
    }
    return true;
}


功能二:負責把關來自外界的輸入

預防各種執行階段中的不可預期現象發生

例子:

export function splitString(arg: unknown): string[] {
    if(typeof arg == 'string') {
        // 檢查完了之後才做我們真正要做的事情,例如:
        return arg.split(',');
        // 此處 TypeScript 會正確地知道 arg 的型別為字串,
        // 因為剛才我們用 typeof 檢查過了。
        // 對於更複雜的型別檢查,可以用 instanceof 關鍵字、
        // 或是使用 TypeScript 的 TypeGuard 來達成,
        // 這是題外話,這邊先不深入討論。
    } else {
        // 否則看要怎麼進行錯誤處理;這邊的方法是傳回預設值
        return [];
        // 或者也可以丟出一個 Error 包含了我們自訂的錯誤訊息
    }
}


養成把對外 API 的參數宣告成 unknown 的好習慣,並且避免使用 TypeScript 中的 as 關鍵字來作型別斷言(取而代之地,應該使用 instanceof 或自訂的 TypeGuard 來確認型別)

any

any 隨便做都行,沒鑑別度

很大的程度上來說,是的;我個人現在是「TypeScript 程式碼中應該要幾乎沒有 any 才對」主張的擁護者。對於很多我接手的程式碼,我都會先搜尋出所有使用到 any 的地方,而它們大多都可以直接換成 unknown 而不用作額外的修改——而如果換成 unknown 之後某個地方因此就出現了編譯錯誤,那幾乎在所有的情況中,那都是突顯出了程式碼具有潛在的異味(bad smell),而釐清為什麼改成 unknown 之後有編譯錯誤、往往能讓程式碼變得更加健全

只有一種情況是我會勉強接受 any 的使用的,那就是當我們引入了一個第三方的型別,我們很清楚其規格、但是我們偏偏又沒有該型別的完整定義檔、而我們自己去寫定義檔又很浪費時間的時候。然而,這樣的使用有幾個前提是應該要遵守的:

  1. 使用了 any 型別的物件應該要充分地被封裝起來,使得使用它的程式碼都非常清楚該變數要怎麼操作。如果有很多程式碼依賴於該物件,那應該要提供一個有良好定義型別的介面來讓其它程式碼間接操作該物件,而不是讓所有程式碼直接取用它。
  2. 對於該物件傳回的值,應該馬上用型別斷言或型別檢查來確定其型別,而不是繼續讓傳回值維持 any 的狀態。

如果沒辦法做到這兩點,那最好還是花一點時間自己把該型別當中會用到的東西宣告一下,這不僅能讓程式碼更有條理,也可以避免很多潛在的手殘可能性。