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

前言

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


往期

  1. "寒冬"三年經驗前端面試總結(含頭條、百度、餓了麼、滴滴等)
  2. "寒冬"三年經驗前端面試總結(含頭條、百度、餓了麼、滴滴等)之CSS篇
  3. "寒冬"三年經驗前端面試總結(含頭條、百度、餓了麼、滴滴等)之手寫題(二)
  4. "寒冬"三年經驗前端面試總結(含頭條、百度、餓了麼、滴滴等)之手寫題(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] = deepClone(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方法。promise

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新增的一個特性,能夠將多維數組展平爲低維數組。若是不傳參默認展平一層,傳參能夠規定展平的層級。bash

// 展平一級
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嗎?app

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;
}
複製代碼

寫在最後

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

相關文章
相關標籤/搜索