實務上 API 所傳回的資料常常掛在 data
Property 上,且資料藏在 Nested Property 下,但 GUI 顯示常只需要一層 Array 而已,這常見需求該如何實現呢 ?
Version
macOS Mojave 10.14.6
VS Code 1.37.1
Quokka 1.0.240
ECMAScript 2019
Ramda 0.26.1
Imperative
let data = {
authors: {
JavaScript: [
'Axel Rauschmayer',
'John Resig'
],
FP: [
'Luis Atencio'
]
},
};
let fn = obj => {
let result = [];
for(let x in obj.authors)
for(let y of obj.authors[x])
result.push(y);
return result;
};
fn(data); // ?
data
為 object,資料都在 authors
property 下,但目前 author 散落在 JavaScript
與 FP
property 下,我們希望結果為一層 array 有所有 author 方便顯示。
Imperative 做法會先宣告回傳的 result
array:
- 使用
for in
loop 將 object 內所有 key 取出 - 再透過
[]
取出 array - 最後使用
for of
將 array 內所有 element 取出
我們發現 imperative 要使用兩層 for
loop。
Functional
let data = {
authors: {
JavaScript: [
'Axel Rauschmayer',
'John Resig'
],
FP: [
'Luis Atencio'
]
}
};
let fn = obj => Object.values(obj.authors).flat();
fn(data); // ?
Functional 會使用 ES2017 的 Object.values()
將 object 所有 value 以 array 呈現。
但 Object.values(obj.authors)
會回傳兩層 array,並非我們要的一層 array,再使用 ES2019 的 Array.prototype.flat()
將 array 攤平。
Ramda
import { values, prop, pipe, flatten } from 'ramda';
let data = {
authors: {
JavaScript: [
'Axel Rauschmayer',
'John Resig'
],
FP: [
'Luis Atencio'
]
}
};
let fn = pipe(
prop('authors'),
values,
flatten
);
fn(data); // ?
既然有 Functional 概念,就很容易用 Ramda 實現了:
- 先使用
prop()
取得data.authors
的 value - 再使用
values()
取得 object 的所有 value,結果為 array - 最後使用
flatten()
將兩層 array 攤平
最後以 pipe()
整合所有流程,非常清楚,並且為 point-free。
Conclusion
Object.values()
與Array.prototype.flat()
為 ECMAScript 較新的 function,但非常實用- Ramda 寫法其實與 ECMAScript 原生寫法觀念相同,只是 Ramda 的 curried function 讓程式碼更精簡
Reference
MDN, Object.values()
MDN, Array.prototype.flat()
Ramda, values()
Ramda, pipe()
Ramda, prop()
Ramda, flatten()