前端面试必备:手写题合集

196 阅读3分钟

前端面试必备:手写题合集

ps:此部分是一面高频手写题,后续会看情况继续整理高频的手写题2.0版本,希望正在找工作的小可爱们都能顺顺利利的入职自己心仪的岗位,和可爱的同事一起共事~笔芯💗

一、防抖和节流

防抖,高频事件触发后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。

function debounce(fn, timing){
   let timer;
   return function(){
     clearTimeout(timer);
     timer = setTimeout(()=>{
       fn();
     }, timing);
   }
 }

节流:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行效率。

function throttle(fn, timing){
   let trigger;
   return function(){
     if(trigger) return;
     trigger = true;
     fn();
     setTimeout(()=>{
       trigger = false;
     }, timing);
   }
 }

小tips:防抖靠定时器控制,节流靠变量控制

二、手写call、apply、bind

call()、apply()、bind()都是用来重定义this这个对象的,bind()返回的是一个新函数,你必须调用它才会被执行。

  • call
Function.prototype.mycall = function (context, ...args){
  const new_this = context || window;
  const func = Symbol('func');
  new_this[func] = this;
  const res = new_this[func](...args);
  delet new_this[func];
  return res;
}
  • apply
Function.prototype.myApply = function (context, args){
  if(!(args instanceof Array)){
    throw new TypeError(`args is not an array!`)
  }
  const new_this = context || window;
  const func = Symbol('func');
  new_this[func] = this;
  const res = new_this[func](...args);
  delet new_this[func];
  return res;
}
  • bind(使用apply实现)
Function.prototype.my_bind = function (context, ...args){
  const new_this = context || window;
  const fn = this;
  return function (){
    return fn.apply(new_this, args)
  }
}

三、实现sleep函数

sleep函数作用是让线程休眠,等到指定时间在重新唤起

//方法一
function sleep1(ms, callback){
  setTimeout(callback, ms)}
sleep1(1000, ()=>{
  console.log(1000)
})
​
//方法二
function sleep2(ms){
​  return new Promise(function(resolve, reject){
    setTimeout(resolve, ms)
  })
}
sleep2(1000).then(()=>{
  console.log(1000)
})
//方法三
function sleep3(ms){
  return new Promise(function(resolve, reject){
    setTimeout(resolve, ms)
  })
}
async function init(){
  await sleep3(1000);
}
init().then(()=>{
  console.log(3000)
})

四、实现Promise

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) {
    var _this = this
    this.state = PENDING; //状态
    this.value = undefined; //成功结果
    this.reason = undefined; //失败原因this.onFulfilled = [];//成功的回调
    this.onRejected = []; //失败的回调
    function resolve(value) {
        if(_this.state === PENDING){
            _this.state = FULFILLED
            _this.value = value
            _this.onFulfilled.forEach(fn => fn(value))
        }
    }
    function reject(reason) {
        if(_this.state === PENDING){
            _this.state = REJECTED
            _this.reason = reason
            _this.onRejected.forEach(fn => fn(reason))
        }
    }
​    try {
        executor(resolve, reject);
    } catch (e) {
        reject(e);
    }
}
Promise.prototype.then = function (onFulfilled, onRejected) {
    const that = this;
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v=>v
    onRejected = typeof onRejected === 'function' ? onRejected : r=>{throw r}
   
    if(this.state === FULFILLED){
        onFulfilled(that.value)
    }
    if(this.state === REJECTED){
        onRejected(that.value)
    }
    if(this.state === PENDING){
        this.onFulfilled.push(onFulfilled)
        this.onRejected.push(onRejected)
    }
};

五、实现Promise.all

Promise.prototype.myAll = function(iterators) {
  const promises = Array.from(iterators)
  const num = promises.length
  let count = 0
  let resolvedValue = new Array(num)
  return new Promise((resolve, reject) => {
    for(let item of promises){
      Promise.resolve(item)
        .then(data => {
          resolvedValue[count++] = data
          // 通过计数器,标记是否所有实例均 fulfilled
          if(count === num){
            resolve(resolvedValue)
          }
        })
        .catch(err => reject(err))
    }
  })
}

六、实现Promise.race

Promise2.race = function(arrP) {
  let hasValue = false
  let hasError = false
  return new Promise2((resolve, reject) => {
    for(let i = 0; i < arrP.length; i++) {
      arrP[i].then(data => {
        !hasValue && !hasError && resolve(data) 
        hasValue = true
      }, error => {
        !hasValue && !hasError &&reject(error)
        hasError = true
      })
    }
  })
}

七、数组去重

// 先说数组去重,主要考察实现的方案要多元化。
//1、利用splice()
var arr = [1,23,1,1,1,3,23,5,6,7,9,9,8,5,5,5,5];
   function norepeat(arr) {
       for(var i = 0; i < arr.length-1; i++){
           for(var j = i+1; j < arr.length; j++){
               if(arr[i]==arr[j]){
                   arr.splice(j,1); 
                   j--;
               }
           }
       }
       return arr;
   }
 var arr2 = norepeat(arr);
 
  //2、借助新数组,indexOf
  var arr = [1,23,1,1,1,3,23,5,6,7,9,9,8,5];
  function norepeat(arr){
          var temp =[];
          for(var i=0;i<arr.length;i++){
           if(arr.indexOf(arr[i]) == i){
               temp.push(arr[i]);
           }
       }
       return temp;
  }
  
  //3、利用filter()
  var arr = ["apple","banana","pear","apple","orange","orange"];
   var arr2 =arr.filter(function(value,index,self){
       return self.indexOf(value) ===index;
   });
   
 //4、利用空对象
  var obj={};
  var arr2=[];
  for(var i=0;i<arr.length;i++){
    if(!obj[arr[i]]){
        obj[arr[i]]=true;
        arr2.push(arr[i]);
     }
  }
  

八、实现一个url分析函数 可以增加参数,可以删除参数

var jsUrlHelper = {
    getUrlParam : function(url, ref) {
        var str = "";
        // 如果不包括此参数
        if (url.indexOf(ref) == -1)
            return "";
        str = url.substr(url.indexOf('?') + 1);
        arr = str.split('&');
        for (i in arr) {
            var paired = arr[i].split('=');
            if (paired[0] == ref) {
                return paired[1];
            }
        
        return "";
    },
    putUrlParam : function(url, ref, value) {
        // 如果没有参数
        if (url.indexOf('?') == -1)
            return url + "?" + ref + "=" + value;
        // 如果不包括此参数
        if (url.indexOf(ref) == -1)
            return url + "&" + ref + "=" + value;
        var arr_url = url.split('?');
        var base = arr_url[0];
        var arr_param = arr_url[1].split('&');
        for (i = 0; i < arr_param.length; i++) {
            var paired = arr_param[i].split('=');
            if (paired[0] == ref) {
                paired[1] = value;
                arr_param[i] = paired.join('=');
                break;
            }
        }
        return base + "?" + arr_param.join('&');
    },
    delUrlParam : function(url, ref) {
        // 如果不包括此参数
        if (url.indexOf(ref) == -1)
            return url;
        var arr_url = url.split('?');
        var base = arr_url[0];
        var arr_param = arr_url[1].split('&');
        var index = -1;
        for (i = 0; i < arr_param.length; i++) {
            var paired = arr_param[i].split('=');
            if (paired[0] == ref) {
                index = i;
                break;
            }
        }
        if (index == -1) {
            return url;
        } else {
            arr_param.splice(index, 1);
            return base + "?" + arr_param.join('&');
        }
    }
   };

九、写一个函数,可以控制最大并发数

//promise方式
function sendResquest(urls, max, callback) { 
    let pending_count = 0, //并发数
    idx = 0;//当前请求的位置
    while (pending_count < max) { 
        _fetch(urls[idx++])
    } 
    async function _fetch(url) { 
        if (!url) return; 
        pending_count++; 
        console.log(url + ':start','并发数: '+pending_count); 
        await fetch(url) 
        pending_count--; 
        console.log(url + ':done','并发数: '+pending_count); 
        _fetch(urls[idx++]); 
        pending_count || callback && callback()
    } 
}

十、实现instanceof

function instance_of(L: Object, R: any){
  let protoChain = Object.getPrototypeOf(L);
  const Lprototype = R.prototype;
  while(protoChain) {
      if(protoChain === Lprototype) {
        return true;
      }
      protoChain = Object.getPrototypeOf(protoChain);
  }
  return false;
}

十一、实现new

// new一个对象的过程
// 创建一个新对象
// this指向这个新对象
// 执行代码,即对this赋值
// 返回this
function New(f) {
    return function () {
        var o = {"__proto__": f.prototype};
        f.apply(o, arguments);//继承父类的属性
        return o; //返回一个Object
    }
}

十二、实现数组flat、fillter等方法

// 数组扁平化Array.prototype.flat() 特性,数组拍平方法也叫做数组扁平化、数组拉平、数组降维
// 不传入参数时,默认拉平一层 ,可以传入一个整数,表示想要拉平的层数
// <=0 返回原数组  , Infinity关键字作为参数时,无论多少层都会拉平转化为一维数组
// 1、 concat + 递归
function flat(arr) {
  let arrResult = [];
  arr.forEach(item => {
    if (Array.isArray(item)) {
      arrResult = arrResult.concat(arguments.callee(item));   // 递归
      // 或者用扩展运算符
      // arrResult.push(...arguments.callee(item));
    } else {
      arrResult.push(item);
    }
  });
  return arrResult;
}
// 用reduce实现
const flat = arr => {
  return arr.reduce((pre, cur) => {
    return pre.concat(Array.isArray(cur) ? flat(cur) : cur);
  }, []);
};

十三、函数 curring

function curry(fn: any) {
  return function judgeCurry(...args: any) {
      return fn.length > args.length ? 
          (...args1: any) => judgeCurry(...args,...args1):
          fn(...args);
  }
}
争取打破一年一记

qrcode_for_gh_d87dccf7ac89_258.jpg