前端開發JS白板編程題目若干
在前端開發參加面試的時候,無論是校招還是社招,往往都會碰到讓我們直接在白紙或者白板上手擼代碼的題目。由于是手擼代碼,這些題目肯定不會過于復雜和冗長,否則面試那么一小會時間根本寫不完。本文總結了幾個我本人在面試中碰到的小問題,暫且記錄下來以供后人參考吧。
1. 實現throttle函數。
throttle函數即節流函數,在underscore和lodash這兩個庫中都有對應的實現。其實現的效果就是在給定的時間間隔內,函數最多只能執行1次。例如有函數A,設定其時間間隔為10s,如果在第0秒的時候已經執行了函數A,然后在第5秒的時候想要再次執行函數A的話,不會立即執行,而是等待5秒鐘再執行。在第7秒的時候想要再次觸發函數A,則第5秒那個函數A直接取消,第7秒這個函數A等待3秒鐘后執行。這樣保證了每個10秒鐘的區間內,函數A只能執行1次。
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常見的場景就是搜索引擎的實時搜索聯想,在你向搜索框輸入文字的過程中,為了避免頻繁地調用后端接口,必須等待輸入完成,間隔一小段時間沒有新的輸入時,再去調用后臺接口獲取搜索聯想詞。
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。
思路:如果某個字符在字符串中只出現了一次,那么該字符在字符串里面的第一次出現和最后一次出現的位置是一樣的,利用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;
}
浙公網安備 33010602011771號