跟 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 文章含有正確的本文網址連結,並且 blog 文章本身支持 microformat,之後你的引用資訊會更新在上面社群迴響的引用評論列表。

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

        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.

        Other Posts