Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第十六週練習題 #16

Open
aszx87410 opened this issue Oct 2, 2020 · 0 comments
Open

第十六週練習題 #16

aszx87410 opened this issue Oct 2, 2020 · 0 comments

Comments

@aszx87410
Copy link
Member

aszx87410 commented Oct 2, 2020

底下提供十六週相關的小題目讓大家練習,都是以後在工作上可能會碰到的案例

這邊我提供了一個 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 去後端拿搜尋的建議,然後顯示在前端。

一個簡單的實作會長這樣:

// 每當 input 的內容有變動,就呼叫 handleChange
$('input').change(handleChange)

function handleChange(e) {
  // 拿到 input 的值
  const value = e.target.value

  // 發 api 去後端拿搜尋建議,然後 render 出來
  // 細節我就不寫了
  getAutoSuggestions(value)
}

可是有一個小問題,那就是現在每打一個字就會發一個 request,例如說我搜尋:lidemy,就會發出六個 request,分別是:

  1. l
  2. li
  3. lid
  4. lide
  5. lidem
  6. 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)
}

memoize

假設我們現在有一個很複雜的函式叫做 complex,它的 input 會是一個數字 n
它是一個 pure function,所以傳進去的 input 如果一樣,output 也會一樣
因為它很複雜,所以每一次計算都至少要 2 秒才會回傳結果

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 的函式

參考解答

https://codesandbox.io/s/closure-homeworks-ans-i5mrd?file=/index.js

比喻來源:Debounce & Throttle — 那些前端開發應該要知道的小事(一)

@aszx87410 aszx87410 changed the title Closure 練習題 第十六週練習題 Oct 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant