最近出去面試了一下,收獲頗多!!!
以前的我,追求實際,比較追求實用價值,然而最近面試,傳說中的面試造火箭,工作擰螺絲,竟然被我遇到了。雖然很多知識點在實際工作中並不經常用到,但人家就是靠這個來篩選人才的!!!
在大學里,你可能會感覺到微積分沒啥用處,去菜市場買菜,你不可能用到微積分吧,但是呢,這個知識卻決定了你能在哪個菜市場買菜。請細品!
關於前端方面,我用的是jQuery,前端采用Ajax請求數據,后端返回JSON數據,得到數據后,再通過jQuery去操作DOM。
這里可能有個誤解,很多人會以為jQuery是一種框架,然而現實並非如此,它只是個工具庫而已,簡化了JavaScript的一些語法。可能很多人用習慣了jQuery后,甚至都分不清jQuery語法跟JavaScript語法。jQuery能做的事情,JavaScript也能做,只是簡單地簡化了一些寫法。
閑話少說,開始正文。
一、談談對閉包的理解
從概念上來講,所謂的閉包指的是一個函數,一個什么樣的函數呢?有權訪問另一個函數作用域中的變量的函數。
直觀點來講,JavaScript的閉包就是函數中嵌套函數。
本質上來講,是因為作用域而產生一種特殊的情況,從而導致函數內部的變量無法進行銷毀。如果再去深究的話,會出現個作用域鏈,這里面比較難理解。也是閉包產生的根本原因。
舉個例子:
function myMethod(){
var num=6;
return function(){
var n=0;
console.log(++n);
console.log(++num);
}
}
myMethod();//執行后,返回的是個方法(就是所謂的閉包),因為這個方法中還用到了myMethod里面的變量num,會導致num無法釋放。
//可以證明
var myFn=myMethod();//將返回的方法用變量保存起來
myFn();//此時的n=1,num=7 num沒有被銷毀,仍然保存着值。這便是閉包的精髓所在,有點像C#/JAVA里面的靜態變量
myFn();//此時的n=1,num=8
myMethod()();//如果這樣運行的話,輸出永遠是n=1,num=7 跟上面是有區別的,上面是用了個變量將其保存了起來。
閉包的優缺點如下:
優點:1、保護函數內部的變量安全,實現封裝
2、可以把這個變量當作緩存來使用
弊端:無法銷毀變量,使用不當,容易造成內存泄漏
你可能會問,閉包的使用場景到底是什么呢?
這個問題可能令你很是疑惑,我也想了很久。直到最近的一次面試,才豁然開朗。接下來看看js的防抖跟節流。
二、談談對防抖的理解
防抖,從字面上來理解,便是防止抖動。
這個,我們應該會經常接觸到,可能自己不知道而已。我們經常使用百度吧,沒事百度搜索一下。在這里,當我們輸入關鍵詞的時候,會出現一些聯想詞,供我們去選擇。這里面便用到了防抖。
試想,如果是我們,怎么去實現這個功能,正常情況下,我們肯定會這樣寫
<input type="text" id="txt_test" />
//相應的js代碼
var txt_test=document.getElementById("txt_test");
txt_test.oninput=function(){
console.log(txt_test.value);
//其他代碼
請求后端數據
}
對應的結果
這樣寫,的確不錯。每輸入一個字符,觸發一次輸入事件。
聯想到實際
現實中使用百度的人成千上萬,那每次輸入一個字符,請求后端一次,這么多人的話同時使用百度的話,那請求也太多了,肯定會導致服務器壓力賊大,我們知道,這些請求中很多是沒有什么實際意義的,基於這種場景,怎么優化呢?
試想一下,現實中,我們是怎么搜索的?
當我們搜索ghost的時候,應該是快速地輸入,不可能一個字符一個字符的輸入的吧,那打字速度也忒慢了吧。當輸入完的時候,肯定會停頓一下,而這時候再去觸發一次輸入事件豈不正好?此時,防抖,應運而生。
function debounce(fn,wait) {
var timeout = null; // 創建一個標記用來存放定時器的返回值
return function () {
clearTimeout(timeout); //清除定時器
//創建新的 setTimeout
timeout = setTimeout(function(){
fn();
}, wait);
};
}
// 處理函數
function handle() {
console.log(document.getElementById("kw").value);
}
//輸入框事件
document.getElementById("kw").addEventListener('input', debounce(handle,5000));
以上的代碼便是百度搜索中,不管怎么輸入,只有在輸入完成后,停頓5s(這個時間故意設置這么長的),才會觸發一次handle方法。
三、談談對節流的理解
我們應該也會經常接觸到,比如打開一個網頁,往下滾動的時候,會出現滾動條,當滾動到一定的程度時,會出現一個返回頂部的按鈕,點擊一下,便會返回到頂部。在這里,便會用到節流。
試想,如果是我們,需要實現以上的功能,我們是如何寫代碼的。
首先,先寫一個div通過position:fixed;display:none;固定到頁面右下角。然后寫一個滾動事件,
window.onscroll=function(e){
//相應的處理代碼
handler();距離多少的位置,顯示按鈕或者隱藏按鈕。
}
function handler(){
console.log("滾動事件觸發");
}
在這里,當我們向下滾動頁面的時候,你會發現,這個onscroll事件觸發的頻率太高太高,稍微向下滾動一丟丟,就已經觸發了很多次,而且其中很多的觸發並沒有實在的意義,如何減少觸發的頻率,減少那么多的計算操作呢?
現實中,屏幕刷新率一般在60HZ,我們看到的靜態畫面並不是完全不動的,只是動的太快,人眼無法覺察出,誤以為是不動的。如果過慢的話,我們自然會看得出來,過快的話,沒啥實際意義,刷新的過快了,通過人眼,我們還是認為屏幕是不動的。
既然這樣,那可不可以這樣?
在人眼識別的范圍內,間接地去觸發這個事件。豈不正好?這時候,節流便誕生了。
所謂的節流呢,其思想指的就是某些代碼不可以在沒有間斷的情況下連續重復執行。類似的還有onresize等事件。
function throttle(fn,delay){
var canRun=true;//通過閉包保存該變量
return function(){
if(!canRun) return;//立刻返回
canRun=false;
setTimeout(function(){
fn();
canRun=true;
},delay);
};
}
function handle(){
console.log(123);
}
window.addEventListener("scroll",throttle(handle,2000));
以上的代碼便是觸發窗口滾動事件后,每2s執行一次handle方法。
總結
以上的防抖跟節流的方法,都是比較基礎的方法。至於怎么升級,就靠個人了。
防抖跟節流都用到了閉包,
使用的都是計時器setTimeout,
防抖是某個事件觸發后幾秒后執行相應的方法,
而節流是某個事件觸發后周期性執行相應的方法。