使用遞歸來去除對象中的 null 字段

太長不看版:

一個函數,若是直接或者間接調用本身,那麼它就是遞歸函數。其中,斐波那契數列就是一個用遞歸解決問題的常見例子,但其實遞歸有着更多的應用好比文件系統的目錄結構,嵌套數據結構的校驗和轉換等數組

什麼是遞歸?

咱們順便來學個單詞: recursion。它是遞歸的意思,有點不直觀,咱們來看看另外一個 curve 曲線,那麼 re-curve 就是不斷重複的曲線了。數據結構

The factorial of a positive integer n, denoted by n!, is the product of all positive integers less than or equal to n.less

整數n的階乘,記作 n!,是全部小於或者等於 n 的整數的結果。好比,要計算 5 的階乘:函數

5! = 1 * 2 * 3 * 4 * 5
   = 2 * 3 * 4 * 5
   = 6 * 4 * 5
   = 24 * 5
複製代碼

若是咱們想計算 6 的階乘,只須要把上面的結果再乘以 6。7 的階乘就是 7 * 6!若是咱們把結果整理成一個表,會發現以下模式:優化

n !n - -
1 1 - -
2 2 * 1 = 2(1!) = 2
3 3 * 2 * 1 = 3(2!) = 6
4 4 * 3 * 2 * 1 = 4(3!) = 24
5 5 * 4 * 3 * 2 * 1 = 5(4!) = 120

能夠看出在表格中的每一行都依賴以前的內容,除了第一行。第一行通常叫作遞歸的基類。這就意味着若是咱們想要計算任何正整數 n 的階乘,咱們從計算 n - 1 開始,而後會計算 n - 2,直到到達基類 !1 = 1 爲止。ui

代碼

下面是遞歸函數的 Javascript 實現:spa

const factorial = n => {
  if (n <= 1) {
    return 1
  }
  return factorial(n - 1) * n
}
複製代碼

用三目來簡寫以下:code

const factorial = n => n <= 1 ? 1 : factorial(n - 1) * n;
複製代碼

若是忘記了基類條件呢?

若是咱們移走以前代碼中的條件判斷,只保留遞歸調用的話:cdn

const factorial = n => factorial(n -1) * n
複製代碼

這樣的調用會引起堆棧溢出,俗稱爆棧,也叫內存泄漏。大多數時候,沒有基類的遞歸調用不該該存在。可是在尾遞歸中有所不一樣。對象

遞歸很酷,可是能作點什麼有用的嗎?

終於要回歸正題了。咱們假設在帶寬有限的狀況下,數據傳輸很慢。因此須要優化數據接口,咱們須要把一個對象中的任意嵌套深度的 null 值給過濾掉,這個時候,遞歸就派上用場了,直接上代碼。

註釋即正文:

const isObject = value => Object(value) === value

const removeNullValues = object =>
  /* `Object.entries()`方法返回一個給定對象自身可枚舉屬性的鍵值對數組,其排列與使用 for...in 循環遍歷該對象時返回的順序一致(區別在於 for-in 循環也枚舉原型鏈中的屬性)。 以上來自MDN的介紹,經過 Object.entries 咱們能夠獲得一個 [key, value] 排列的數組,方便接下來的 reduce 直接使用。 */
  Object.entries(object).reduce((acc, [key, value]) => {
  // 當值爲 null 時,過濾掉
  if (value === null) {
    return acc
  }
  if (isObject(value)) {
    // 若是value 是一個引用類型,也就是說 value 裏面還有對象,咱們就須要再次調用函數自身進一步解析裏面的值,過濾 null
    const filteredValue = removeNullValues(value)
    // 也有可能這個對象是一個空對象,也是咱們不想要的,剔除空對象操做,好比: dolor: {}
    if (Object.entries(filteredValue).length === 0) {
      return acc;
    }
    // 最後函數從這裏結束並返回,函數removeNullValues 會獲得正確的結果
    return { ...acc, [key]: filteredValue }
  }
  // 這一步操做是跟reduce用法相關,咱們須要收集每次遍歷後獲取的有效屬性, acc 是一個累計值
  return { ...acc, [key]: value }
}, {})

removeNullvalues({
  foo: 'foo',
  bar: null,
  baz: {
    qux: null,
    quux: 'quux',
    corge: {
      lorem: null,
      ipsum: null,
      dolor: {}
    }
  }
})

// [object Object] {
// baz: [object Object] {
// quux: "quux"
// },
// foo: "foo"
// }
複製代碼

本文完,感謝閱讀!

pic
相關文章
相關標籤/搜索