Open aszx87410 opened 4 years ago
底下提供十六週相關的小題目讓大家練習,都是以後在工作上可能會碰到的案例
這邊我提供了一個 codesandbox 的環境,你的任務是實作出 Robot 這個 class 以及 debounce 跟 memoize 這兩個 function,裡面有提供相對應的測試檔,測試過了應該就是通過了:https://codesandbox.io/s/closure-homeworks-vh5j3?file=/index.js
至於題目的敘述請參考下面,另外,請勿針對底下那兩個 function 的關鍵字做搜尋,因為你一搜尋了,答案就出現了。如果想確認正確的行為是什麼,可以參考測試檔。
請你寫出一個 Robot 的 class,初始化的時候可以設置座標 x 跟 y 接著 Robot 會有兩個方法,getCurrentPosition 跟 go,前者會回傳現在機器人所在的 x 與 y 座標,後者可以讓機器人往東南西北任一方向移動,需要傳進 'N', "E", 'S', 'W' 任何一個字串,代表要往哪一個方向走
'N', "E", 'S', 'W'
這個世界是我們所熟悉的二維座標系,因此往北走 Y 座標會增加,往南走 Y 座標會減少,往東走 X 座標會增加,往西走 X 座標會減少
在程式的領域中有兩個技巧滿常會用到,分別是 throttle 與 debounce,這邊我就只介紹什麼是 debounce。
舉例來說,假設今天有個 auto complete 的 input,像是 Google 搜尋那樣,在你打字的時候,就會邊發 API request 去後端拿搜尋的建議,然後顯示在前端。
一個簡單的實作會長這樣:
// 每當 input 的內容有變動,就呼叫 handleChange $('input').change(handleChange) function handleChange(e) { // 拿到 input 的值 const value = e.target.value // 發 api 去後端拿搜尋建議,然後 render 出來 // 細節我就不寫了 getAutoSuggestions(value) }
可是有一個小問題,那就是現在每打一個字就會發一個 request,例如說我搜尋:lidemy,就會發出六個 request,分別是:
lidemy
可是這樣是很沒有效率的,因為在我打字的時候,其實真正需要搜尋的結果只有最後的字串 lidemy,中間那些都是可以跳過的。
那解決方法是什麼呢?
有一個解法叫做 debounce,之前看到一個比喻滿傳神的,就是搭公車。司機什麼時候會關車門?確保真的都沒有人要上車以後。而為了確保這件事,就必須等待。
例如說現在第一個人上車了,那司機就等 2 秒後再關門,如果等了 1 秒之後有第二個人上車了,他就再等兩秒。這兩秒間如果又有人上車了,那就再等 2 秒,所以有可能會一直等下去。那如果 2 秒內沒人上車了,司機就可以開車了。
這概念就叫做 debounce,你有一個 threshold(閾值),在這裡面如果再度觸發這個事件,就再繼續等待,反之則做原本要做的事。
以上面 input 的案例來講,通常我們會把 debounce 的 threshold 設在 250ms,意思就是你打完一個字之後,要 250ms 後才會真的去發 api 拿東西,如果你在 250ms 以內又打了新的字,就會再等 250ms。
以正常的使用狀況來講,我打 lidemy 這六個字,每個字中間的間隔不會超過 250ms,所以 api 會在我打完 lidemy 的 y 以後過 250ms 才觸發,這樣就只會觸發一次而已。
因此你的任務呢,就是實作出一個 debounce 的函式,用起來會像這樣:
// 每當 input 的內容有變動,就呼叫 handleChange $('input').change(handleChange) // 讓原本發後端 api 的函式 debounce const debouncedFn = debounce(getAutoSuggestions, 250) function handleChange(e) { // 拿到 input 的值 const value = e.target.value // 發 api 去後端拿搜尋建議,然後 render 出來 // 細節我就不寫了 // 在 250ms 內重複呼叫的話不會有反應 debouncedFn(value) }
假設我們現在有一個很複雜的函式叫做 complex,它的 input 會是一個數字 n 它是一個 pure function,所以傳進去的 input 如果一樣,output 也會一樣 因為它很複雜,所以每一次計算都至少要 2 秒才會回傳結果
complex
console.log(complex(10)) // 等 2 秒才輸出結果
但因為它是 pure function,所以我們想在呼叫他的時候,順便把他的結果記下來 如果以後用同樣的參數去呼叫這個函式的話,就把之前記下來的結果回傳就好,因為一定是正確的 可是我們並不想直接去更動 complex 這個函式內部的東西 因此,我們需要一個叫做 memoize 的 function,它可以接收一個函式作為參數,並且幫這個函式加上「記憶」的功能,範例如下:
console.log(complex(10)) // 等 2 秒才輸出結果 console.log(complex(10)) // 等 2 秒才輸出結果 const memoizeFn = memoize(complex) console.log(memoizeFn(10)) // 等 2 秒才輸出結果 console.log(memoizeFn(10)) // 立刻輸出結果,因為我們把之前 complex(10) 回傳過的值記起來了
而你的任務就是實作出這個 memoize 的函式
底下提供十六週相關的小題目讓大家練習,都是以後在工作上可能會碰到的案例
這邊我提供了一個 codesandbox 的環境,你的任務是實作出 Robot 這個 class 以及 debounce 跟 memoize 這兩個 function,裡面有提供相對應的測試檔,測試過了應該就是通過了:https://codesandbox.io/s/closure-homeworks-vh5j3?file=/index.js
至於題目的敘述請參考下面,另外,請勿針對底下那兩個 function 的關鍵字做搜尋,因為你一搜尋了,答案就出現了。如果想確認正確的行為是什麼,可以參考測試檔。
Robot
請你寫出一個 Robot 的 class,初始化的時候可以設置座標 x 跟 y 接著 Robot 會有兩個方法,getCurrentPosition 跟 go,前者會回傳現在機器人所在的 x 與 y 座標,後者可以讓機器人往東南西北任一方向移動,需要傳進
'N', "E", 'S', 'W'
任何一個字串,代表要往哪一個方向走這個世界是我們所熟悉的二維座標系,因此往北走 Y 座標會增加,往南走 Y 座標會減少,往東走 X 座標會增加,往西走 X 座標會減少
Debounce
在程式的領域中有兩個技巧滿常會用到,分別是 throttle 與 debounce,這邊我就只介紹什麼是 debounce。
舉例來說,假設今天有個 auto complete 的 input,像是 Google 搜尋那樣,在你打字的時候,就會邊發 API request 去後端拿搜尋的建議,然後顯示在前端。
一個簡單的實作會長這樣:
可是有一個小問題,那就是現在每打一個字就會發一個 request,例如說我搜尋:
lidemy
,就會發出六個 request,分別是:可是這樣是很沒有效率的,因為在我打字的時候,其實真正需要搜尋的結果只有最後的字串 lidemy,中間那些都是可以跳過的。
那解決方法是什麼呢?
有一個解法叫做 debounce,之前看到一個比喻滿傳神的,就是搭公車。司機什麼時候會關車門?確保真的都沒有人要上車以後。而為了確保這件事,就必須等待。
例如說現在第一個人上車了,那司機就等 2 秒後再關門,如果等了 1 秒之後有第二個人上車了,他就再等兩秒。這兩秒間如果又有人上車了,那就再等 2 秒,所以有可能會一直等下去。那如果 2 秒內沒人上車了,司機就可以開車了。
這概念就叫做 debounce,你有一個 threshold(閾值),在這裡面如果再度觸發這個事件,就再繼續等待,反之則做原本要做的事。
以上面 input 的案例來講,通常我們會把 debounce 的 threshold 設在 250ms,意思就是你打完一個字之後,要 250ms 後才會真的去發 api 拿東西,如果你在 250ms 以內又打了新的字,就會再等 250ms。
以正常的使用狀況來講,我打 lidemy 這六個字,每個字中間的間隔不會超過 250ms,所以 api 會在我打完 lidemy 的 y 以後過 250ms 才觸發,這樣就只會觸發一次而已。
因此你的任務呢,就是實作出一個 debounce 的函式,用起來會像這樣:
memoize
假設我們現在有一個很複雜的函式叫做
complex
,它的 input 會是一個數字 n 它是一個 pure function,所以傳進去的 input 如果一樣,output 也會一樣 因為它很複雜,所以每一次計算都至少要 2 秒才會回傳結果但因為它是 pure function,所以我們想在呼叫他的時候,順便把他的結果記下來 如果以後用同樣的參數去呼叫這個函式的話,就把之前記下來的結果回傳就好,因為一定是正確的 可是我們並不想直接去更動 complex 這個函式內部的東西 因此,我們需要一個叫做 memoize 的 function,它可以接收一個函式作為參數,並且幫這個函式加上「記憶」的功能,範例如下:
而你的任務就是實作出這個 memoize 的函式
參考解答
[https://codesandbox.io/s/closure-homeworks-ans-i5mrd?file=/index.js](https://codesandbox.io/s/closure-homeworks-ans-i5mrd?file=/index.js) 比喻來源:[Debounce & Throttle — 那些前端開發應該要知道的小事(一)](https://medium.com/@alexian853/debounce-throttle-%E9%82%A3%E4%BA%9B%E5%89%8D%E7%AB%AF%E9%96%8B%E7%99%BC%E6%87%89%E8%A9%B2%E8%A6%81%E7%9F%A5%E9%81%93%E7%9A%84%E5%B0%8F%E4%BA%8B-%E4%B8%80-76a73a8cbc39)