Josh Hsu

常見的前端面試手寫考題,deepClone、debounce、throttle

> 大陸面試題常考的八股文題目

常見的前端面試手寫考題,deepClone、debounce、throttle

相關函式的詳細解釋這邊就不做特別說明,這篇只專注在 code 的部分

#deepClone

請實作一個簡易版的 deepClone

(2023/5/22 更新) Web API 有一個叫做structuredClone的 API,已經可以實現 deepClone 的功能,但是各家的瀏覽器都是近幾個版本才支援的,所以如果有舊版本瀏覽器的話,要做好兼容性。

// 最簡易,但要考慮會有什麼限制? 為什麼這樣可以? const cloned = JSON.parse(JSON.stringify(objectToClone))
/** * 簡易版 deepClone * 有許多 Edge cases 沒有考慮到, * 如果是產品的見還是用 loadsh的 _.cloneDeep 比較保險 * * 用遞歸的方式判斷假如是object就不斷在進到下一層, * 若不是object的話就賦值給 target * @param {Object} source * @returns {Object} */ export function deepClone(source) { if (!source && typeof source !== 'object') { throw new Error('Error arguments', 'deepClone') } // 可以用 source.constructor 或是 Array.isArray(source) 來判斷是 Array 還是 Object const target = source.constructor === Array ? [] : {} Object.keys(source).forEach((keys) => { if (source[keys] && typeof source[keys] === 'object') { target[keys] = deepClone(source[keys]) } else { target[keys] = source[keys] } }) return target }

延伸問題:

#debounce

請實作一個 debounce 的 function,以及請說明 debounce 的應用場合

/** * 簡易版 * @param {Function} func func The function to debounce. * @param {number} wait * @return {Function} Returns the new debounced function. */ function debounce(fun, delay) { return function (args) { let that = this let _args = args // 每次執行的時候重置setTimeout clearTimeout(fun.time) fun.time = setTimeout(function () { // 執行傳入的fun1(透過call方法傳遞參數_args) fun.call(that, _args) }, delay) } }
/** * 簡易版 + 立即執行 * @param {Function} func func The function to debounce. * @param {number} wait * @param {boolean} immediate is immediate execute * @return {Function} Returns the new debounced function. */ function debounce(func, wait, immediate) { let timeout, args, context, timestamp, result const later = function () { // 據上一次觸發時間間隔 const last = +new Date() - timestamp // 上次被包裝函數被調用時間間隔 last 小於設定時間間隔 wait if (last < wait && last > 0) { timeout = setTimeout(later, wait - last) } else { timeout = null // 如果設定為 immediate === true,因為開始邊界已經調用過了此處無需調用 if (!immediate) { result = func.apply(context, args) if (!timeout) context = args = null } } } return function (...args) { context = this timestamp = +new Date() const callNow = immediate && !timeout // 如果延時不存在,重新設定延時 if (!timeout) timeout = setTimeout(later, wait) if (callNow) { result = func.apply(context, args) context = args = null } return result } }

#使用情境

#Throttle

function throttle(func, timeout = 250) { let last let timer return function () { const context = this const args = arguments const now = +new Date() if (last && now < last + timeout) { clearTimeout(timer) timer = setTimeout(function () { last = now func.apply(context, args) }, timeout) } else { last = now func.apply(context, args) } } }

#使用情境

See all posts