🔥🔥代码手撕十三金钗🔥🔥再也不怕面试官让我手撕了

面试了两个月,发现大大小小的公司无论面试多久,最后必须来两三道手撕题,考验候选人的代码能力

平时简单题手到擒来,但到了面试官面前就大脑宕机

简简单单一道【实现apply】都能卡住,我的总结是还得多练,同一道题多打几次,面试的时候才能思路清晰

整理了最基础的常见手撕,啃下这些,基本可以应对70%的手撕题

当然大厂手撕并不都是简单基础题,很多都是在这13道基础上拓展,先练好这13道基础题,面试的时候就算run不通,也可以先说个大概思路,从面试官那里获取一点提示

稍复杂的手撕,后续更新~~

curry(柯里化)

function curry(fn: any) {

  return function judgeCurry(...args: any) {

      return fn.length > args.length ?

          (...args1: any) => judgeCurry(...args,...args1):

          fn(...args);

  }

}

 

compose(函数组合)

function compose(...args: any[]) {

  return (subArgs: any) => {

// 方法一

    // for(let i = args.length - 1; i >= 0; i--) {

    //   res = args[i](res);

    // }

// 方法二

    return args.reverse().reduce((acc, func,index) => {

      return func(acc);

    }, subArgs);

  }

}

 

pipe(函数管道)

export function pipe(...args: any[]) {

  return (subArgs: any) => {

// 方法一

    // for(let i = args.length - 1; i >= 0; i--) {

    //   res = args[i](res);

    // }

// 方法二

    return args.reduce((acc, func,index) => {

      return func(acc);

    }, subArgs);

  }

}

 

throttle(函数节流)

function throttle(fn: any, wait: number){

  let last: any;

  return function() {

    let now: any = Date.now();

    // 初次执行

    if (!last) {

      fn.apply(this, arguments);

      last = now;

      return;

    }

    // 以后触发,需要判断是否到延迟

    if(now - last >= wait) {

      fn.apply(this, arguments);

      last = now;

    }

  }

}

 

debounce(函数防抖)

function debounce(func: any, delay: number) {              

    // 初次触发定时器为null,后面产生一份定时器并记下定时器id

    let timer: any = null;

    // 闭包使定时器id逃逸   

    return function() {                             

        let args = arguments;  

        // 如果已有定时器id,则需要清除,重新开始延迟执行           

        if (timer) {

            clearTimeout(timer);

            timer = null;                                   

        }

        

        timer = setTimeout( () => {

            func.apply(this, args);

            // 销毁定时器id,以便下次节流函数触发                       

            timer = null;                    

        }, delay);

    }        

}

formatMoney(千分位)

function fmoney(num: number){

    /* 正则实现 */

    // 参考:https://www.cnblogs.com/lvmylife/p/8287247.html

    let [integer, decimal] = String(num).split('.');

    let regExp = /\d{1,3}(?=(\d{3})+$)/g;

    integer = integer.replace(regExp, '$&,');

    return `${integer}${decimal === undefined ? '': '.'+decimal}`;

    // 正则解释

    // 正则表达式 \d{1,3}(?=(\d{3})+$)  表示前面有1~3个数字,后面的至少由一组3个数字结尾

    // 先行肯定断言(?=)会作为匹配校验,但不会出现在匹配结果字符串里面

    // ?=表示正向引用,可以作为匹配的条件,但匹配到的内容不获取,并且作为下一次查询的开始

    // $& 表示与正则表达式相匹配的内容,具体的可查看 w3school的replace()方法

 

    /* Number.prototype.toLocaleString()实现 */

    // Number.prototype.toLocaleString()

    // return num.toLocaleString('en');

 

    /* Intl.NumberFormat().format(number)实现 */

    // Intl.NumberFormat().format(number)

    // return Intl.NumberFormat('en').format(num);

 

    // reduce 方案

    // let arr = String(num).split('.');

    // let char = arr[0].split('').reverse();   

    // let IntStr = char.reduce((acc, value, index) => {

    //     return `${index % 3 === 0 ? String(value)+',' : String(value)}${acc}`;

    // }, '').slice(0, -1);

    // return `${IntStr}${arr[1]? '.'+arr[1] : '' }`;

}

 

deepClone(深拷贝)

// 说明:通过new WeakMap()来避免循环引用(拷贝引用类型时并保存其地址,

// 后面遇到引用类型先检查是否已经保存了)

 

// 通过Reflect.ownKeys(obj)遍历出obj自身的所有可枚举和不可枚举的属性以及symbol属性

// 拷贝对应属性的属性描述符

 

function checkType(obj) {

    const type = Object.prototype.toString.call(obj);

    return type.slice(8, -1);

}

 

// 深拷贝(hash = new WeakMap()考虑循环引用的问题)

export function deepClone(obj, hash = new WeakMap()) {

    if (checkType(obj) === 'RegExp') {

        // regExp.source 正则对象的源模式文本;

        // regExp.flags 正则表达式对象的标志字符串;

        // regExp.lastIndex 下次匹配开始的字符串索引位置

        let temp = new RegExp(obj.source, obj.flags);

        temp.lastIndex = obj.lastIndex;

        return temp;

    }

    if (checkType(obj) === 'Date') {

        return new Date(obj);

    }

    // 非复杂类型(null、undefined、string、number、symbol、boolean、function)

    if (obj === null || typeof obj !== 'object') {

        return obj;

    }

    // 还可以扩展其他类型。。。

    // 与后面hash.set()防止循环引用

    if (hash.has(obj)) {

        return hash.get(obj);

    }

 

    let newObj = new obj.constructor();

    hash.set(obj, newObj);

    // Object.keys(obj)类型于 for in 和 obj.hasOwnProperty

    // 是否应该拷贝自身属性(可枚举的和不可枚举的以及symbol)

    Reflect.ownKeys(obj).forEach(function (key) {

        if (typeof obj[key] === 'object' && obj[key] !== null) {

            newObj[key] = deepClone(obj[key], hash);

        } else {

            // 直接赋值

            // newObj[key] = obj[key];

            // 是否应该保留属性描述符

            Object.defineProperty(newObj, key, Object.getOwnPropertyDescriptor(obj, key));

        }

    });

 

    return newObj;

}

 

模拟instanceof

function instance_of(L: Object, R: any){

    let protoChain = Object.getPrototypeOf(L);

    const Lprototype = R.prototype;

    // 最坏情况递归查到Object.prototype === null

    while(protoChain) {

        // 两个对象指向同一个内存地址,则为同一个对象

        if(protoChain === Lprototype) {

          return true;

        }

        protoChain = Object.getPrototypeOf(protoChain);

    }

    // 找到终点还没找到,那就没有了呗

    return false;

  }  

实现call方法

Function.prototype.myCall = function myCall() {

    let [thisArg, ...args] = Array.from(arguments);

    if (!thisArg) {

        //context 为 null 或者是 undefined

        thisArg = typeof window === 'undefined' ? global : window;

    }

    // this 的指向的是当前函数 func (func.call)

    // 为thisArg对象添加func方法,func方法又指向myCall,所以在func中this指向thisArg

    thisArg.func = this;

    // 执行函数

    let result = thisArg.func(...args);

    // thisArg 上并没有 func 属性,因此需要移除

    delete thisArg.func;

    return result;

}  

 

实现apply方法

Function.prototype.myApply = function myApply() {

  // 第一个参数为this对象,第二个参数为数组(与myCall唯一的区别就在第二个参数是数组)

  let [thisArg, args] = Array.from(arguments);

  if (!thisArg) {

      //context 为 null 或者是 undefined

      thisArg = typeof window === 'undefined' ? global : window;

  }

  // this 的指向的是当前函数 func (func.call)

  thisArg.func = this;

  // 执行函数

  let result = thisArg.func(...args);

  // thisArg 上并没有 func 属性,因此需要移除

  delete thisArg.func;

  return result;

}

 

实现bind方法

Function.prototype.myBind = function myBind() {

  let [thisArg, ...args] = [...arguments];

  if (!thisArg) {

      //context 为 null 或者是 undefined

      thisArg = typeof window === 'undefined' ? global : window;

  }

  let that = this;

 

  return function() {

      // 防止第二次调用 func 是,该func已经被delete了,需要重新赋值

      if(!thisArg.func) {

        thisArg.func = that;

      }

      let result = thisArg.func(...args);

      // thisArg原本没有func方法

      delete thisArg.func;

      return result;

  }

}

 

模拟Promise.all(多个Promise并行执行)

目前还存在参数适配的问题

var p1 = function(){

  return new Promise((resolve, reject) => {setTimeout(function(){resolve('12')}, 1000)})

};

var p2 = function(){

  return new Promise((resolve, reject) => {setTimeout(function(){resolve(2)}, 2000)})

};

var p3 = function(){

  return new Promise((resolve, reject) => {setTimeout(function(){resolve(3)}, 1000)})

};

function promiseAll(tasks) {

  let ary = new Array(tasks.length).fill(1).map(item => {return {val: undefined, success: false}});

  return new Promise((resolve, reject) => {

    for(let i = 0; i < tasks.length; i++) {

      tasks[i]().then(res => {

        ary[i].val = res;

        ary[i].success = true;

        if(ary.every(item => item.success === true)){

          resolve(ary.map(item => item.val))

        }

      }).catch(err => {

        reject(err);

      });

    }

  });

}

// test

promiseAll([p1, p2, p3]).then(res => console.log(res)).catch(err => {

  console.log(err);

});

 

多个Promise串行执行(两种方式)

function parallelPromises1(tasks){

  var result = [];

  return tasks.reduce((accumulator,item,index)=>{

    return accumulator.then(res => {

        item = typeof item === 'function' ? item() : item;

        return item.then(res => {

              result[index] = res

              return index == tasks.length - 1 ? result : item

        })

    })

  }, )

}

 

async function parallelPromises2(tasks) {

  let ary = [];

  for (let task of tasks) {

    let temp = await task();

    ary.push(temp);

  }

  return ary;

}

#面试##牛客创作充电计划##前端##如何判断面试是否凉了##23届找工作求助阵地#
全部评论
再面下去,我都要变手撕鸡了
2 回复
分享
发布于 2023-03-27 13:57 新疆
说思路也可以吗?
1 回复
分享
发布于 2023-03-27 13:57 湖南
滴滴
校招火热招聘中
官网直投

相关推荐

8 24 评论
分享
牛客网
牛客企业服务