大厂js基础面试-深挖到底系列2-手撸代码都在这了

545 阅读4分钟

深拷贝

浅拷贝只是拷贝了对象(引用类型)的指针,在修改对象时会影响到原来对象(基础类型不会影响)

深拷贝就是为了弥补浅拷贝的不足,说白了就是遇到对象或者数组时进行递归,将他们拆分成基础类型,这样就实现互不影响了。话不多说,直接撸

function deepClone(result,target){
    //判断是否为数组
    result = Array.isArray(target) ? [] : {};
    for( var i in target ){
        if(target[i] == 'object'){
            deepClone(result[i],target[i])
        }else{
            result[i] == target[i]
        }
    }
    return result;
}

promise

理解promise:promise只负责返回一个成功或者失败的状态(利用js提供的resolve和reject方法),然后就没用了,后续的要使用then接收状态来操作

1、new Promise传入的executor方法代码是同步执行的;

2、promise对象的状态有三种:pending(等待态),resolved(成功态),rejected(失败态),只能从等待态转化成成功态或失败态;

3、executor中执行resolve()方法,表示将转化为成功态,promise.then调用时执行成功的方法,executor中执行reject()方法,表示将转化为成功态,promise.then调用时执行失败的方法。

function myPromise(executor){
  this.status = 'pending' ;
  this.value = null;
  this.reason = null;
  this.resCallback = [];//存放then成功回调
  this.rejCallback = [];//存放then失败回调
  
  const resolve = (value) => {
      if(this.status === 'pending') {
          this.status = 'resolved';
          this.value = value;
          this.resCallback.forEach(fn => {
             fn()
      })
  }
  const rejected = (reason) => {
      if(this.status ==' pending') {
          this.status = 'rejected';
          this.reason = reason;
          this.rejCallback.forEach(fn => {
              fn()
          })
      }
  }
}
//1、then 生成一个新的 promise
//2、then同步调用:状态改变直接执行onFulfilled和onRejected
//3、then异步调用:(setTimeout为了表达异步的意思,其实内部并不是使用setTime实现的)
状态为pending,则将结果存储到函数数组中,此时then还没有执行,只用于存储状态,当调用
resolve和rejected时在执行。
//4、为了实现链式调用,所以then要返回一个状态。
myPromise.prototype.then = function(onFulfilled,onRejected){
    switch(this.statu){
        case fulfilled:
            setTimeout(() => {
                try {
                      resolve(onFulfilled(this.value));   
                } catch{
                    reject(reason);
                }
            }, 0);
            break;
        case rejected:
            setTimeout(() => {
                try {
                      resolve(onRejected(this.reason));   
                } catch{
                    reject(reason);
                }
            }, 0);
            break;
        case PENDING:
            this.resCallback.push(() => {
                setTimeout(() => {
                    onFulfilled(this.value)
                }, 0);
            })
            this.rejCallback.push(() => {
                setTimeout(() => {
                    onRejected(this.reason)
                })
            })
    }
}

3、单例模式

立即执行函数加闭包

var alone =(function(){
   var a = function(){
       //...code
   };
   return a
})()

4、bind

bind的两个特性,柯里化和new,当new的时候,bind的this层面不起作用,只有后面传入的参数还起作用。下面简单实现柯里化

function myBind(context, ...args){
    if(typeof context !== 'function'){//判断函数
        throw new TypeError("error");
    }
    const self = this;
    function myFunc(...args2){
        return self.apply(context,args.concat(args2)//实现函数柯里化
    }
}

继续优化

当使用new时,会创建一个空对象,将this指向这个空对象,空对象的隐式原型(proto)指向构造器的显示原型(myFunc.prototype)

function myBind(context, ...args){
    if(typeof context !== 'function'){//判断函数
        throw new TypeError("error");
    }
    const self = this;
    const myFn = function(){}
    function myFunc(...args2){
        return self.apply(
            this instanceof myFn ? this : context,
            args1.concat(args2)
       )
    }
    myFn.prototype = this.prototype;
    myFunc.prototype = new myFn();
    
    return myFunc;
}

参考链接:www.cnblogs.com/goloving/p/…

5、函数柯里化

说白了就是使用闭包把参数存起来,当参数数量足够执行函数了,就开始执行函数

function currying(fn,...args){
    if(args.length >= fn.length){//参数数量够了,返回
        return fn(args);
    }else{//参数不够,递归返回一个闭包,存入传进的参数并返回
        return (...args2) => currying(fn,...args,...args2)
    }
}

6、es5继承

寄生组合继承

function child(){
    parent.call(this);
}
var myProto = Object.create(parent.prototype);
myProto.constructor = child;
child.prototype = myProto;

7、实现instanceof

递归的判断左式的隐式原型连(即左式的原型链)是否等于右式的显示原型

function myInstanceof(target,origin){
    const proto = target.__proto__;
    if(proto){
        if(origin.prototype === proto){
            return true;
        }else{
            myInstanceof(proto,origin)
        }
    }else{
        return false;
    }
}

8、防抖

:触发事件后的n秒内,如果再次触发事件,就会重新计算时间,只有在n秒不再触发事件,n秒后执行事件。

就像王者荣回城一样,回程的几秒钟内,如果再次点击回城,就会重新计算回城,时间到了才回城。

function boun(enent, time){
    let timer = null;//定义一个为空的定时器
    return function(...args){
        clearTime(timer);//清空定时器
        timer = setTimeout(() => {//定时器是一个time秒后执行
            event.apply(this,args);
        },time);
    };
}

9、节流

:不管事件的触发频率有多高,单位时间内只执行一次

举个栗子:就像王者荣耀的技能,例如冷却时间是三秒,那么这个技能3秒内只能是放一次,3秒后才能释放下一次。

function thro(event,time){
    let timer = null; //定义空的定时器
    return function(...args){
        if(!timer){//如果此时定时器为空,那么执行定时器
            timer = setTimeout(() => {
                timer = null;
                event.apply(this,args);
            },time); //定时时间到将定时器置为空。
        }
    }
}