博客 / 詳情

返回

“寒冬”三年經驗前端面試總結(含頭條、百度、餓了麼、滴滴等)之手寫題(一)

前言

不論是寒冬還是暖冬,找工作之前都需要做好充足的準備,面試的時候才能做到遊刃有餘。此文是把我最近找工作準備的以及筆試面試中涉及到的手寫題做一個總結。給自己,也給需要的同學。
手寫題是比較好準備的一個環節,大部分公司考察的題也就那麼多,大都不會超出範圍。


往期

  1. "寒冬"三年經驗前端面試總結(含頭條、百度、餓了麼、滴滴等)
  2. "寒冬"三年經驗前端面試總結(含頭條、百度、餓了麼、滴滴等)之手寫題(二)
  3. "寒冬"三年經驗前端面試總結(含頭條、百度、餓了麼、滴滴等)之手寫題(promise篇)

防抖 & 節流

原理都是利用閉包保存變量。防抖是任務頻繁觸發的情況下,只有任務觸發的間隔超過指定間隔的時候,任務才會執行,一般用於輸入框實時搜索;節流是規定函數在指定的時間間隔內只執行一次,一般用於scroll事件。

// 防抖
function debounce(fn,time){
    let timer = null;
    return function(){
        if(timer){
            clearTimeout(timer)
        }
        timer = setTimeout(()=>{
            fn.apply(this,arguments)
        },time)
    }
}
// 節流
function throttle(fn,time){
    let canRun = true;
    return function(){
        if(!canRun){
            return
        }
        canRun = false;
        setTimeout(() => {
            fn.apply(this,arguments);
            canRun = true;
        },time)
    }
}

深拷貝

深拷貝是一個老生常談的問題。幾年前面試就考,現在面試仍然會考。主要考察的是遞歸、數組和對象的存儲。

function deepClone(obj) {
    var result = Array.isArray(obj) ? [] : {};
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (typeof obj[key] === 'object' && obj[key]!==null) {
          result[key] = deepCopy(obj[key]); 
        } else {
          result[key] = obj[key];
        }
      }
    }
    return result;
  }
function deepClone(arr){
    return JSON.parse(JSON.stringify(arr))
}

數組亂序

亂序也是常考的一道題。

// 取巧的一種算法,但是每個位置亂序的概率不同
function mixArr(arr){
    return arr.sort(() => {
        return Math.random() - 0.5;
    })
}
// 著名的Fisher–Yates shuffle 洗牌算法
function shuffle(arr){
    let m = arr.length;
    while(m > 1){
        let index = parseInt(Math.random() * m--);
        [arr[index],arr[m]] = [arr[m],arr[index]];
    }
    return arr;
}

數組去重

數組去重的方法有很多種,如果要是手寫的話,一般我都會寫下面這種。也會順便説一下ES6的set方法。

function removeDup(arr){
    var result = [];
    var hashMap = {};
    for(var i = 0; i < arr.length; i++){
        var temp = arr[i]
        if(!hashMap[temp]){
            hashMap[temp] = true
            result.push(temp)
        }
    }
    return result;
}
Array.from(new Set(arr))
[...new Set(arr)]

數組flat

數組flat方法是ES6新增的一個特性,可以將多維數組展平為低維數組。如果不傳參默認展平一層,傳參可以規定展平的層級。

// 展平一級
function flat(arr){
    var result = [];
    for(var i = 0; i < arr.length; i++){
        if(Array.isArray(arr[i])){
            result = result.concat(flat(arr[i]))
        }else{
            result.push(arr[i]);
        }
    }
    return result;
}
//展平多層
 function flattenByDeep(array,deep){
      var result = [];
      for(var i = 0 ; i < array.length; i++){
          if(Array.isArray(array[i]) && deep > 1){
                result = result.concat(flattenByDeep(array[i],deep -1))
          }else{
                result.push(array[i])
          }
      }
      return result;
  }

數組filter

filter方法經常用,實現起來也比較容易。需要注意的就是filter接收的參數依次為數組當前元素、數組index、整個數組,並返回結果為ture的元素。

Array.prototype.filter = function(fn,context){
    if(typeof fn != 'function'){
        throw new TypeError(`${fn} is not a function`)
    }
    let arr = this;
    let reuslt = []
    for(var i = 0;i < arr.length; i++){
        let temp= fn.call(context,arr[i],i,arr);
        if(temp){
            result.push(arr[i]);
        }
    }
    return result
}

手寫call & apply & bind

call、apply、bind是ES5中能改變this指向的方法。一般都會問一下這三個方法的區別。call和apply的傳參不同,call接收逗號分隔的參數,apply接收數組(如何記不清這兩個方法的區別的話,可以記apply接收array,都是a開頭的,這樣比較好記),調用都會立即執行。而bind調用完返回的是一個函數,需要再次調用才會執行。
接下來就會引申到能實現一個call/apply嗎?或者能用apply實現一個bind嗎?

Function.prototype.myCall = function(context){ 
    if(typeof this != 'function'){
        throw new TypeError('this is not a function')
    }
    context.fn = this;
    var arr = [];
    for(var i = 1; i< arguments.length; i++){
        arr.push('argument[' + i + ']')
    }
    var result = eval('context.fn(' +arr+ ')');
    delete context.fn;
    return result;
}
Function.prototype.myApply = function(context,arr){ 
    if(typeof this != 'function'){
        throw new TypeError('this is not a function')
    }
    context.fn = this;
    var result= [];
    if(!arr){
        result = context.fn()
    }else{
        var args = [];
        for(var i = 1; i< arr.length; i++){
            args.push('arr[' + i + ']')
        }
        result = eval('context.fn(' +args+ ')');
    }
    delete context.fn;
    return result;
}
Function.prototype.myBind = function(context){
    if(typeof this != 'function'){
        throw new TypeError('this is not a function')
    }
    var self = this;
    var args = Array.prototype.slice.call(arguments,1);
    var F = function(){};
    F.prototype = this.prototype;
    var bound = function(){
        var bindArgs = Array.prototype.slice.call(arguments);
        return self.apply(this instanceof F ? this: context, args.concat(bindArgs))
    };
    bound.prototype = new F();
    return bound;
}

寫在最後

有錯誤之處還請小夥伴們及時指出,以免誤人子弟。想看往期內容,翻到頁面最上面有鏈接~

user avatar laughingzhu 頭像 lanlanjintianhenhappy 頭像 huishou 頭像 fish_60c2dbded700f 頭像 esunr 頭像 _raymond 頭像 uncletong_doge 頭像 suporka 頭像 mulander 頭像 tingzhong666 頭像 iymxpc3k 頭像 niumingxin 頭像
31 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.