一個函數,若是直接或者間接調用本身,那麼它就是遞歸函數。其中,斐波那契數列就是一個用遞歸解決問題的常見例子,但其實遞歸有着更多的應用好比文件系統的目錄結構,嵌套數據結構的校驗和轉換等數組
咱們順便來學個單詞: 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"
// }
複製代碼
本文完,感謝閱讀!