JS 中創建自定義排序方法

爲了保證的可讀性,本文采用意譯而非直譯。


一般情況咱們排序大都按數字或字母順序,但也有一些情況下,咱們可能需要自定義排序順序。


在此之前先簡單介紹一下 reduce 方法:


語法:arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])


callback:執行數組中每個值的函數,包含四個參數:


accumulator:累計器累計回調的返回值; 它是上一次調用回調時返回的累積值,或initialValue(見於下方)。


currentValue:數組中正在處理的元素。


currentIndex (可選):數組中正在處理的當前元素的索引。如果提供了initialValue,則起始索引號爲0,否則爲1。


array(可選): 調用 reduce() 的數組


initialValue(可選):作爲第一次調用 callback 函數時的第一個參數的值。如果沒有提供初始值,則將使用數組中的第一個元素。在沒有初始值的空數組上調用 reduce 將報錯。


rudeuce 過程描述:


回調函數第一次執行時,accumulator 和currentValue的取值有兩種情況:如果調用reduce()時提供了initialValue,accumulator取值爲initialValue,currentValue取數組中的第一個值;如果沒有提供 initialValue,那麼accumulator取數組中的第一個值,currentValue取數組中的第二個值。


回到原文:


如下面的例子所示,咱們想讓 inProgress 在第一位,接着是 todo,然後是 done。


const tasks = [

  {id:1, title: 'Job A', status: 'done'},

  {id:2, title: 'Job B', status: 'inProgress'},

  {id:3, title: 'Job C', status: 'todo'},

  {id:4, title: 'Job D', status: 'inProgress'},

  {id:5, title: 'Job E', status: 'todo'}

]

首先按照所需的排序順序創建一個數組。


const sortBy = ['inProgress', 'todo', 'done']

使用reduce來創建一個函數,參數爲一個數組,最後輸出以數組項爲鍵,索引爲值,如 {inProgress:0,todo:1,done:2}。


const sortByObject = data => data.reduce(

  (obj,item,index) => ({

    ...obj,

    [item]:index

}), {}

)

console.log(sortByObject(sortBy))

/* {inProgress: 0, todo: 1, done: 2} */

這樣就有了排序設置,咱們可以將它與一個可重用的函數放在一起,該函數傳入一個數組(data)、一個sortby數組和一個sortField,這樣咱們就知道要在哪個字段上排序:


const customSort = ({data, sortBy, sortField}) => {

  const sortByObject = sortBy.reduce(

  (obj, item, index) => ({

      ...obj,

      [item]: index

  }), {})

  return data.sort((a, b) => sortByObject[a[sortField]] - sortByObject[b[sortField]])

}

 

console.log(customSort({data:tasks, sortBy, sortField: 'status'}))

這樣就可以按照咱們的自定義順序排序,不過還有一個問題,如果列表中有一個status不同的項(不在咱們的排序順序中),就會出現問題。因此,爲了處理這個問題,咱們需要設置一個默認的sort字段來捕獲排序中不需要的所有項。


const tasksWithDefault = tasks.map(item => (

  {  

    ...item,

    sortStatus: sortBy.includes(item.status) ? item.status:'other'

  })

 )

這次傳遞的是更新後的sort字段,那麼現在就有了正確的排序順序,列表底部還有包含狀態爲 other 的項目。


完整代碼:


const tasks = [

  { id: 1, title: "Job A", status: "done" },

  { id: 2, title: "Job B", status: "inProgress" },

  { id: 3, title: "Job C", status: "todo" },

  { id: 3, title: "Job D", status: "onHold" },

  { id: 4, title: "Job E", status: "inProgress" },

  { id: 5, title: "Job F", status: "todo" }

];

 

const sortBy = ["inProgress", "todo", "done"];

 

const customSort = ({ data, sortBy, sortField }) => {

  const sortByObject = sortBy.reduce(

    (obj, item, index) => ({

      ...obj,

      [item]: index

    }),

    {}

  );

  return data.sort(

    (a, b) => sortByObject[a[sortField]] - sortByObject[b[sortField]]

  );

};

 

const tasksWithDefault = tasks.map(item => ({

  ...item,

  sortStatus: sortBy.includes(item.status) ? item.status : "other"

}));

console.log(

  customSort({

    data: tasksWithDefault,

    sortBy: [...sortBy, "other"],

    sortField: "sortStatus"

  })

);

運行結果:




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章