在前端開發參加面試的時候,不管是校招仍是社招,每每都會碰到讓咱們直接在白紙或者白板上手擼代碼的題目。因爲是手擼代碼,這些題目確定不會過於複雜和冗長,不然面試那麼一小會時間根本寫不完。本文總結了幾個我本人在面試中碰到的小問題,暫且記錄下來以供後人參考吧。javascript
1. 實現throttle函數。前端
throttle函數即節流函數,在underscore和lodash這兩個庫中都有對應的實現。其實現的效果就是在給定的時間間隔內,函數最多隻能執行1次。例若有函數A,設定其時間間隔爲10s,若是在第0秒的時候已經執行了函數A,而後在第5秒的時候想要再次執行函數A的話,不會當即執行,而是等待5秒鐘再執行。在第7秒的時候想要再次觸發函數A,則第5秒那個函數A直接取消,第7秒這個函數A等待3秒鐘後執行。這樣保證了每一個10秒鐘的區間內,函數A只能執行1次。java
var throttle = function (func, wait) { var timeout = null; // setTimeout的返回值 var previous = 0; // 上次執行此函數的時間 return function () { var now = new Date(); var remaining = wait - (now - previous); // 距離設定的時間間隔還剩多少時間 var context = this; var args = arguments; // 清除已經設定的定時器,若是timeout=null,則這下面句沒有任何效果 clearTimeout(timeout); // 如今距離上次執行已經超過了設定間隔,直接執行該函數 if (remaining <= 0) { previous = now; timeout = null; func.apply(context, args); return; } // 還沒到時間間隔就再次想執行,則清除以前設置的定時器,重設定時器等待一段時間後執行函數 timeout = setTimeout(function () { previous = now; timeout = null; func.apply(context, args); }, remaining); }; };
2. 實現debounce函數。面試
debounce即防抖函數。可參考underscore或lodash庫對此函數的實現。若是函數A防抖而且時間間隔爲10秒,那麼當想要執行函數A時,不會當即執行而是等待10秒以後再執行。若是第5秒又想要執行函數A了,那第10秒要執行的A直接被取消,而是從新開始10秒計時,也就是等到第15秒纔會執行函數A。debounce常見的場景就是搜索引擎的實時搜索聯想,在你向搜索框輸入文字的過程當中,爲了不頻繁地調用後端接口,必須等待輸入完成,間隔一小段時間沒有新的輸入時,再去調用後臺接口獲取搜索聯想詞。ajax
var debounce = function (task, wait) { var timeout = null; return function () { var context = this; var arg = arguments; clearTimeout(timeout); timeout = setTimeout(function () { task.apply(context, arg); }, wait); } };
3. 假設目前已經有函數$ajax,主要功能是向後臺發送一個請求,結果以Promise方式返回,如$ajax(option).then(successCb).catch(failCb),其中successCb和failCb分別是成功和失敗時候的回調函數。請實現一個函數myAjax,返回值依然是Promise,但要求加入重試功能,該函數內部依然是使用$ajax實現,只不過在$ajax失敗一次以後間隔1秒鐘再重試1次,再失敗再隔1秒後重試,直到重試到第5次,若是全都失敗了,那myAjax所返回的Promise則reject,只要有任意一次成功,則中止重試,直接resolve。算法
var myAjax = (function () { var failCount = 0; return function (option) { return new Promise((resolve, reject) => { $ajax(option).then(() => { failCount = 0; resolve(); }).catch(() => { failCount++; if (failCount >= 5) { failCount = 0; reject(); return; } setTimeout(function () { myAjax(option).then(() => { resolve(); }).catch(() => { reject(); }); }, 1000); }) }) } })();
4. 實現wait函數,即延遲執行某函數,使用方法爲wait(1000).then(myFunction),即等到1秒鐘以後執行myFunction。後端
var wait = function (time) { return new Promise((resolve, reject) => { setTimeout(function () { resolve(); }, time); }) };
5. 編寫一個函數,將嵌套的數組轉化成扁平的數組,例如:輸入 [1, 2, 3, [4, 5, [6]], [6, 8] ],輸出 [1, 2, 3, 4, 5, 6, 6, 8]。數組
var flatten = function (arr) { let result = []; for (let val of arr) { if (Array.isArray(val)) { result.push(...flatten(val)); } else { result.push(val); } } return result; }
6. 編寫一個函數,輸入一個字符串,將字符串中第一個只出現一次的字符返回。不存在的話返回false。app
思路:若是某個字符在字符串中只出現了一次,那麼該字符在字符串裏面的第一次出現和最後一次出現的位置是同樣的,利用String.prototype.indexOf和String.prototype.lastIndexOf求出一個字符在字符串裏面第一次出現和最後一次出現的位置,判斷是否相等來決定是否只出現了一次。以下:函數
var uniqueChar = function (str) { let len = str.length; for (let i = 0; i < len; i++){ let chr = str[i]; if (i === str.lastIndexOf(chr)){ return chr; } } return false; }
不過上面這個算法有個小瑕疵,就是時間複雜度是O(n^2),並不算過高效。本着用空間換時間的辦法,咱們能夠換一種思路,先遍歷一次字符串,期間以每一個字符爲hash的key,hash的value爲該字符出現的次數。這樣一次遍歷下來就構建完成了一個hash表,而後再遍歷一次,查看每一個字符在hash表裏面的value是否是1,若是是1,則中止遍歷直接返回該字符。
var uniqueChar = function (str) { let obj = {}; for (let i = 0; i < str.length; i++) { let chr = str[i]; if (obj.hasOwnProperty(chr)) { obj[chr] ++; } else { obj[chr] = 1; } } for (let i = 0; i < str.length; i++) { let chr = str[i]; if (obj[chr] === 1) { return chr; } } return false; }
7. 隨便找一個Array.prototype裏面的方法,本身手動實現一下。
鏈接若干個數組的concat方法: Array.prototype.concat = function () { var result = [...this]; for (var i = 0; i < arguments.length; i++) { if (Array.isArray(arguments[i])) { result.push(...arguments[i]); } else { result.push(arguments[i]); } } return result; }