跟 Array push reduce 和 Object property mutation 說再見,JavaScript 優雅的處理資料結構技巧 - Jason's Web Memo

跟 Array push reduce 和 Object property mutation 說再見,JavaScript 優雅的處理資料結構技巧

資料結構的處理其實在前端還蠻常見的,但是常常因為大量使用迴圈 if else 等 imperative 語法而讓程式看起來複雜難懂,本文簡單介紹一些現代 JavaScript 中的一些技巧讓你可以優雅的處理資料結構

資料結構的處理其實在前端還蠻常見的,但是常常因為大量使用迴圈 if else 等 imperative 語法而讓程式看起來複雜難懂,本文簡單介紹一些現代 JavaScript 中的一些技巧讓你可以優雅的處理資料結構

conditional 在 Object 放入  property

如何在某些條件下在一個 Object 中放入某個欄位,舉個例子,如果 itemList 的長度大於 0 就在 result object 放入 itemList,比較傳統的寫法如下

const data = {
user: "aaa",
};

const result = Object.assign({}, data);

if (itemList.length) {
result.itemList = itemList;
}

但是在 Object 裡面善用 spread operator 就可以不需要對 result 進行修改,宣告 result 的時候就可以一步到位

const data = {
user: "aaa",
};

const result = {
...data,
...(itemList.length > 0 && { itemList }),
};

conditional 在 Array 放入 item

假設今天我們要根據使用者有沒有登入在 couponList 頂端放入會員專屬的 memberCoupons,傳統的寫法可以寫得像是這樣

const couponList = [];

if (isLogin) {
couponList.concat(memberCoupons);
}

couponList.concat(generalCoupons);

但是在 Array 裡面善用 spread operator,就可以在宣告 couponList 的時候一步到位處理掉

const couponList = [...(isLogin ? [memberCoupons] : []), ...generalCoupons];

要注意這邊 spread operator 在 Array 裡面後面一定要接 array,所以不能用 && 取值,要改用  ? : ternary operator , 另外在 Array 裡面也不能 spread Object

對 Object key value 做類似於 Array 的 map filter 處理

Array 裡面有方便 map filter 讓我們可以輕鬆的對 item 做操作,但是 Object 的資料結構裡面卻沒有,我們今天如果要把 data 裡頭的 value 濾掉 1000 以下並乘於 0.5 比較傳統的可以用 for in 這樣寫

const data = {
123321: 1400,
123322: 800,
123323: 1200,
};

const result = {};

for (let key in data) {
if (data[key] > 1000) {
result[key] = data[key] * 0.5;
}
}

如果你熟悉 reduce,喜歡遵守 immuatable 原則,可能會改寫成如下

const result = Object.keys(data).reduce(
(acc, key) => (data[key] > 1000 ? { ...acc, [key]: data[key] * 0.5 } : acc),
[]
);

雖然你沒有修改任何的 Object ,但是 spread object 的做法效能複雜度不是很好 O(n^2),reduce 也沒有辦法像是 map filter 容易理解

如果你知道 lodash 有類似 map filter 的 utils function,可以改寫如下

_.mapValues(
_.pickBy(data, (val) => val > 1000),
(val) => val * 0.5
);

但是一旦用到 lodash,就要小心的處理 bundle size 問題

ECMAScript 2017 Obejct.entries and ECMAScript 2019 Object.fromEntries

ECMAScript 最近幾年出了兩個可以解決這個問題的 api ,Object.entries 可以把 Object 轉成 [key, value] 的 tuple Array,Object.fromEntries 則可以把 [key, value] 的 tuple Array 轉成 Object,所以可以用這兩個 api 改寫

const result = Object.fromEntries(
Object.entries(data)
.filter(([key, value]) => value > 1000)
.map(([key, value]) => [key, value * 0.5])
);

Pipe Operator

另外 ECMAScript stage 1 proposal pipe operator 可以讓你避免巢狀嵌套的寫法,看起來又更漂亮了

const result =
data
|> Object.entries
|> (entries) => entries.filter(([key, value]) => value > 1000)
|> (entries) => entries.map(([key, value]) => value * 0.5);
|> Object.fromEntries

不過要小心這語法未來可能有兩種走向,投資有賺有賠,使用前請先詳看說明書 https://github.com/tc39/proposal-pipeline-operator

Webmention 社群迴響 0

喜歡 0
    轉推 0
      引用或評論 0

        用 Webmentions 參與社群迴響

        若你的 blog 文章想要引用本文,請確認 blog 文章含有正確的本文網址連結,並且 blog 文章本身支持 microformat,歡迎透過下方表單用將你的 blog 文章網址傳送給我,之後你的引用資訊會更新在上面社群迴響的引用評論列表。

        社群迴響將不定期更新,不保證同步,同時有資料缺漏的可能性。

        Jason Chen - Yahoo Taiwan EC Web frontend engineer currently. Write something about web and React.js here

        Jason Chen

        Yahoo Taiwan Sr. Frontend Engineer. Write something about web and React.js here.


        訂閱 blog 掌握最新文章

        訂閱 RSS 更新,複製 xml 網址

        加入 Google Groups 訂閱電子報

        追蹤我的 Medium,文章異步更新

        Other Posts