[翻譯]map和reduce,處理資料結構的利器

白吟靈發表於2019-02-25

原文地址:codeburst.io/writing-jav…
作者:Shivek Khurana
簡介:本文是一份編寫優雅、簡潔和函式式ES6程式碼的快捷清單。

現如今JavaScript有許多問題,但是詞法並不是其中之一。不管是三元運算子,還是map/reduce等ES6方法,亦或是擴充套件運算子(…)都是非常強大的工具。

除了能夠保證可讀性以及準確性,這些方法還有助於實現不可變性,因為這些方法會返回新的資料,而處理前的原始資料並不會被修改。這樣的處理風格很適合redux以及Fractal

話不多說,讓我們開始吧。

一個簡單的reduce實踐

當你想要將多個資料放進一個例項中時,你可以使用一個reducer。

const posts = [
  {id: 1, upVotes: 2},
  {id: 2, upVotes: 89},
  {id: 3, upVotes: 1}
];
const totalUpvotes = posts.reduce((totalUpvotes, currentPost) =>     
  totalUpvotes + currentPost.upVotes, //reducer函式
  0 // 初始化投票數為0
);
console.log(totalUpvotes)//輸出投票總數:92
複製程式碼

傳給reduce的第一個引數函式還可以增加2個引數:

  1. 第三個引數:每個元素在原資料結構中的位置,比如陣列下標。
  2. 第四個引數:呼叫reduce方法的資料集合,比如例子中的posts。
    所以,一個reducer的完全體應該是下面這樣的:
collection.reduce(
  (accumulator, currentElement, currentIndex, collectionCopy) => 
    {/*function body*/},
    initialAccumulatorValue
);
複製程式碼

一個簡單的map實踐

map方法的作用在於處理流式資料,比如陣列。我們可以把它想象成所有元素都要經過的一個轉換器。

const integers = [1, 2, 3, 4, 6, 7];
const twoXIntegers = integers.map(i => i*2);
// twoXIntegers現在是 [2, 4, 6, 8, 12, 14],而integers不發生變化。
複製程式碼

一個簡單的find實踐

find返回陣列或類似結構中滿足條件的第一個元素。

const posts = [
  {id: 1, title: `Title 1`},
  {id: 2, title: `Title 2`}
];
// 找出id為1的posts
const title = posts.find(p => p.id === 1).title;
複製程式碼

一個簡單的filter實踐

filter方法可以篩除陣列和類似結構中不滿足條件的元素,並返回滿足條件的元素組成的陣列。

const integers = [1, 2, 3, 4, 6, 7];
const evenIntegers = integers.filter(i => i%2 === 0);
// evenIntegers的值為[2, 4, 6]
複製程式碼

向陣列中新增元素

如果你要建立一個無限滾動的ui元件(比如本文後面提到的例子),可以使用擴充套件運算子這個非常有用的詞法。

const books = [`Positioning by Trout`, `War by Green`];
const newBooks = [...books, `HWFIF by Carnegie`];
// newBooks are now [`Positioning by Trout`, `War by Green`, `HWFIF // by Carnegie`]
複製程式碼

為一個陣列建立檢視

如果需要實現使用者從購物車中刪除物品,但是又不想破壞原來的購物車列表,可以使用filter方法。

const myId = 6;
const userIds = [1, 5, 7, 3, 6];
const allButMe = userIds.filter(id => id !== myId);
// allButMe is [1, 5, 7, 3]
複製程式碼

譯者注:這裡我猜測作者是不想修改原來的陣列所以使用的filter,但是不能理解為什麼要舉購物車的例子。

向物件陣列新增新元素

const books = [];
const newBook = {title: `Alice in wonderland`, id: 1};
const updatedBooks = [...books, newBook];
//updatedBooks的值為[{title: `Alice in wonderland`, id: 1}]
複製程式碼

books這個變數我們沒有給出定義,但是不要緊,我們使用了擴充套件運算子,它並不會因此失效。

為物件新增一組鍵值對

const user = {name: `Shivek Khurana`};
const updatedUser = {...user, age: 23};
//updatedUser的值為:{name: `Shivek Khurana`, age: 23}
複製程式碼

使用變數作為鍵名為物件新增鍵值對

const dynamicKey = `wearsSpectacles`;
const user = {name: `Shivek Khurana`};
const updatedUser = {...user, [dynamicKey]: true};
// updatedUser is {name: `Shivek Khurana`, wearsSpectacles: true}
複製程式碼

修改陣列中滿足條件的元素物件

const posts = [
  {id: 1, title: `Title 1`},
  {id: 2, title: `Title 2`}
];
const updatedPosts = posts.map(p => p.id !== 1 ?
  p : {...p, title: `Updated Title 1`}
);
/*
updatedPosts is now 
[
  {id: 1, title: `Updated Title 1`},
  {id: 2, title: `Title 2`}
];
*/
複製程式碼

找出陣列中滿足條件的元素

const posts = [
  {id: 1, title: `Title 1`},
  {id: 2, title: `Title 2`}
];
const postInQuestion = posts.find(p => p.id === 2);
// postInQuestion now holds {id: 2, title: `Title 2`}
複製程式碼

譯者注:奇怪啊,這不就是之前find的簡單實踐嗎?

刪除目標物件的一組屬性

const user = {name: `Shivek Khurana`, age: 23, password: `SantaCl@use`};
const userWithoutPassword = Object.keys(user)
  .filter(key => key !== `password`)
  .map(key => {[key]: user[key]})
  .reduce((accumulator, current) => 
    ({...accumulator, ...current}),
    {}
  )
;
// userWithoutPassword becomes {name: `Shivek Khurana`, age: 23}
複製程式碼

感謝Kevin Bradley提供了一個更優雅的方法:

const user = {name: `Shivek Khurana`, age: 23, password: `SantaCl@use`};
const userWithoutPassword = (({name, age}) => ({name, age}))(user);
複製程式碼

他還表示這個方法在物件屬性更少時也能發揮作用。

將物件轉化成請求串

你也許幾乎遇不到這個需求,但是有時候在別的地方會給你一點啟發。

const params = {color: `red`, minPrice: 8000, maxPrice: 10000};
const query = `?` + Object.keys(params)
  .map(k =>   
    encodeURIComponent(k) + `=` + encodeURIComponent(params[k])
  )
  .join(`&`)
;
// encodeURIComponent將對特殊字元進行編碼。
// query is now "color=red&minPrice=8000&maxPrice=10000"
複製程式碼

獲取陣列中某一物件的下標

const posts = [
  {id: 13, title: `Title 221`},
  {id: 5, title: `Title 102`},
  {id: 131, title: `Title 18`},
  {id: 55, title: `Title 234`}
];
// 找到id為131的元素
const requiredIndex = posts.map(p => p.id).indexOf(131);
複製程式碼

譯者注:這裡我覺得方法很繁瑣。可以使用findIndex方法:const requiredIndex = posts.findIndex(obj=>obj.id===131);,同樣能獲取到下標值2。

作者總結

有了這些強大的方法,我希望你的程式碼會變得越來越穩定和一絲不苟。當你的團隊中有一個新的開發者加入時,可以向他推薦這篇文章,讓他了解以前不知道的祕密。

這個翻譯專案才開始,以後會翻譯越來越多的作品。我會努力堅持的。
專案地址:github.com/WhiteYin/tr…

相關文章